@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.
- package/README.md +45 -3
- package/dist/{ChatProfileModal-DKuxJsdM.js → ChatProfileModal-Bf5jGPBZ.js} +566 -562
- package/dist/FilePreviewModal-Bwx0RZZw.js +1763 -0
- package/dist/{ManageDataModal-Dw4dCQll.js → ManageDataModal-Dhkp0LWH.js} +20 -20
- package/dist/{MarkdownBody-xtKDMR0h.js → MarkdownBody-_sUhW2O8.js} +1 -1
- package/dist/{MessageSearchModal-BVKU6H3v.js → MessageSearchModal-rwwWrILl.js} +106 -114
- package/dist/{PublicChatsModal-CscOnVaQ.js → PublicChatsModal-Byso6_vt.js} +13 -13
- package/dist/{SideDrawer-WneDrrWG.js → SideDrawer-CQPOf0ek.js} +38 -38
- package/dist/{UserProfileModal-CMHFq1I9.js → UserProfileModal-Vj2kICvc.js} +10 -10
- package/dist/{UserSettingsModal-BoZXZ0oR.js → UserSettingsModal-CioX4ZIV.js} +5 -5
- package/dist/{VideoCallOverlay-CQNi7wp5.js → VideoCallOverlay-DodAkiam.js} +3824 -3708
- package/dist/{VisibilityModal-BPsNiMzJ.js → VisibilityModal-CIl7rkBM.js} +12 -12
- package/dist/assets/icons.d.ts +2 -3
- package/dist/components/Files/fileCategory.d.ts +4 -2
- package/dist/components/InputComponents/MentionDropdown.d.ts +2 -0
- package/dist/components/MainComponents/AlbumGrid.d.ts +22 -0
- package/dist/components/MainComponents/AttachmentList.d.ts +6 -6
- package/dist/components/MainComponents/ImageUnavailable.d.ts +21 -0
- package/dist/components/MainComponents/MediaUploadOverlay.d.ts +31 -0
- package/dist/components/MainComponents/MessageContainer.d.ts +3 -0
- package/dist/components/MainComponents/scrollAnchor.d.ts +19 -0
- package/dist/components/MainComponents/useJumpToMessage.d.ts +42 -11
- package/dist/components/MainComponents/useScrollAnchor.d.ts +29 -0
- package/dist/components/MessageBubble/MediaCaption.d.ts +9 -0
- package/dist/components/MessageBubble/MessageAvatarPhoto.d.ts +17 -0
- package/dist/components/MessageBubble/MessageReaction.d.ts +6 -0
- package/dist/components/MessageBubble/QuickReplies.d.ts +2 -0
- package/dist/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +8 -10
- package/dist/components/Modals/FilePreviewModal/ImageLightbox.d.ts +4 -0
- package/dist/components/Modals/FilePreviewModal/PdfView.d.ts +4 -0
- package/dist/components/Modals/FilePreviewModal/ViewerChrome.d.ts +64 -0
- package/dist/components/Modals/MessageSearchModal/MessageHitResults.d.ts +5 -0
- package/dist/components/Modals/styledModalComponents.d.ts +0 -8
- package/dist/components/RoomComponents/LastMessageItem.d.ts +2 -0
- package/dist/components/RoomComponents/styled/LastMessageMedia.d.ts +19 -0
- package/dist/components/RoomComponents/styled/LastTextMessage.d.ts +2 -2
- package/dist/components/RoomComponents/styled/StyledRoomComponents.d.ts +10 -3
- package/dist/components/VideoCalls/VideoCallSession.d.ts +13 -0
- package/dist/components/styled/FileCard.d.ts +20 -0
- package/dist/components/styled/MediaSurface.d.ts +50 -0
- package/dist/components/styled/MessageImage.d.ts +9 -10
- package/dist/components/styled/SendInput.d.ts +12 -2
- package/dist/components/styled/StyledComponents.d.ts +69 -2
- package/dist/components/styled/StyledInputComponents/MediaComponents.d.ts +36 -24
- package/dist/components/styled/UnsupportedType.d.ts +1 -0
- package/dist/components/styled/VideoMessage.d.ts +11 -6
- package/dist/e2ee/callKey.d.ts +32 -0
- package/dist/e2ee/fileEnvelope.d.ts +16 -5
- package/dist/e2ee/omemo.d.ts +18 -0
- package/dist/firebase-messaging-sw.js +20 -3
- package/dist/{handleCopyClick-B70vLjJD.js → handleCopyClick-DGaZhy_u.js} +1 -1
- package/dist/helpers/albumLayout.d.ts +53 -0
- package/dist/helpers/attachments.d.ts +22 -1
- package/dist/helpers/avatarImageCache.d.ts +9 -0
- package/dist/helpers/caption.d.ts +63 -0
- package/dist/helpers/checkUniqueUsers.d.ts +2 -2
- package/dist/helpers/composerFocus.d.ts +22 -0
- package/dist/helpers/createMainMessageForThread.d.ts +1 -1
- package/dist/helpers/dedupeMembers.d.ts +10 -0
- package/dist/helpers/downloadFile.d.ts +19 -0
- package/dist/helpers/fileKind.d.ts +17 -0
- package/dist/helpers/historyPreloadConfig.d.ts +25 -0
- package/dist/helpers/historyPreloadScheduler.d.ts +3 -0
- package/dist/helpers/insertMessageWithDelimiter.d.ts +1 -0
- package/dist/helpers/isMessageSearchEnabled.d.ts +9 -0
- package/dist/helpers/jumpThread.d.ts +56 -0
- package/dist/helpers/jumpWindow.d.ts +73 -0
- package/dist/helpers/lastMessagePreview.d.ts +55 -0
- package/dist/helpers/mapWithConcurrency.d.ts +8 -0
- package/dist/helpers/mediaBox.d.ts +110 -0
- package/dist/helpers/mediaBubble.d.ts +39 -0
- package/dist/helpers/mediaLabel.d.ts +10 -0
- package/dist/helpers/mediaSendRetry.d.ts +25 -0
- package/dist/helpers/messageRuns.d.ts +10 -0
- package/dist/helpers/openThreadForJump.d.ts +26 -0
- package/dist/helpers/pdf/loadPdfjs.d.ts +8 -1
- package/dist/helpers/repairFilenameEncoding.d.ts +11 -0
- package/dist/helpers/roomImageGallery.d.ts +34 -0
- package/dist/helpers/roomUserCount.d.ts +19 -0
- package/dist/helpers/safeUrl.d.ts +15 -0
- package/dist/helpers/secureFileUrl.d.ts +4 -1
- package/dist/helpers/userResolver.d.ts +57 -0
- package/dist/helpers/viewerSender.d.ts +47 -0
- package/dist/helpers/xmppIdShape.d.ts +1 -1
- package/dist/hooks/useAvatarImage.d.ts +21 -0
- package/dist/hooks/useChatWrapperInit.d.ts +6 -0
- package/dist/hooks/useIsMobileViewport.d.ts +5 -0
- package/dist/hooks/useMediaProbe.d.ts +40 -0
- package/dist/hooks/usePaneWidthVar.d.ts +11 -0
- package/dist/hooks/usePdfThumbnail.d.ts +2 -2
- package/dist/hooks/usePrefersReducedMotion.d.ts +2 -0
- package/dist/hooks/useRoomDirectory.d.ts +11 -0
- package/dist/hooks/useSendMessage.d.ts +4 -1
- package/dist/{main-rJpE4hh-.js → main-CUB_w8AZ.js} +29136 -24217
- package/dist/main.css +1 -1
- package/dist/main.js +16 -16
- package/dist/networking/api-requests/auth.api.d.ts +2 -0
- package/dist/networking/api-requests/roomMembers.api.d.ts +18 -0
- package/dist/networking/callKeyStanza.d.ts +7 -0
- package/dist/networking/ethoraEvents.d.ts +44 -0
- package/dist/networking/stanzaHandlers.d.ts +6 -4
- package/dist/networking/xmpp/allRoomPresences.xmpp.d.ts +18 -1
- package/dist/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -1
- package/dist/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +2 -0
- package/dist/networking/xmpp/sendMediaMessage.xmpp.d.ts +8 -0
- package/dist/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +2 -0
- package/dist/networking/xmppClient.d.ts +61 -2
- package/dist/roomStore/Middleware/jumpThreadMiddleware.d.ts +2 -0
- package/dist/roomStore/callSlice.d.ts +6 -1
- package/dist/roomStore/index.d.ts +22 -0
- package/dist/roomStore/roomsSlice.d.ts +51 -4
- package/dist/roomStore/safeKey.d.ts +12 -0
- package/dist/roomStore/usersSetCap.d.ts +15 -0
- package/dist/styles/motion.d.ts +22 -2
- package/dist/types/models/attachment.model.d.ts +19 -0
- package/dist/types/models/config.model.d.ts +98 -5
- package/dist/types/models/customComponents.model.d.ts +2 -0
- package/dist/types/models/message.model.d.ts +9 -0
- package/dist/types/models/modal.model.d.ts +19 -0
- package/dist/types/models/room.model.d.ts +30 -0
- package/dist/types/models/xmpp.model.d.ts +24 -1
- package/dist/utils/messageNotificationContent.d.ts +34 -0
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/public/firebase-messaging-sw.js +20 -3
- package/dist/FilePreviewModal-BcaSoO3-.js +0 -743
- package/dist/components/MainComponents/computeAnchoredScrollTop.d.ts +0 -9
- package/dist/components/Modals/NewChatModal/UpdNewChatModal.d.ts +0 -3
- package/dist/components/RoomComponents/styled/LastAudioMessage.d.ts +0 -6
- package/dist/components/RoomComponents/styled/LastMessageFile.d.ts +0 -6
- package/dist/components/RoomComponents/styled/LastMessagePhoto.d.ts +0 -6
- package/dist/components/RoomComponents/styled/LastMessageVideo.d.ts +0 -6
- package/dist/components/SortDropDown/index.d.ts +0 -8
|
@@ -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<
|
|
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
|
-
/**
|
|
6
|
-
export declare const
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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;
|
|
@@ -42,21 +42,88 @@ export declare const UserName: import('styled-components/dist/types').IStyledCom
|
|
|
42
42
|
export declare const InputContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
43
43
|
export declare const MessageInput: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, never>> & string;
|
|
44
44
|
export declare const SendButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
45
|
+
/**
|
|
46
|
+
* How far a reaction row hangs below the bubble's bottom edge, in px. The row
|
|
47
|
+
* straddles the edge, so half of it (12px) is inside the bubble and the other
|
|
48
|
+
* half is the only space the message row reserves below it.
|
|
49
|
+
*/
|
|
50
|
+
export declare const REACTION_HANG_PX = 12;
|
|
51
|
+
/** Clear space between the lowest reaction chip and the next bubble, in px. */
|
|
52
|
+
export declare const REACTION_CLEAR_PX = 4;
|
|
53
|
+
/** Vertical gap below a message that is followed by the same sender, in px. */
|
|
54
|
+
export declare const RUN_GAP_PX = 2;
|
|
55
|
+
/** Vertical gap below the last message of a run, before the next sender, in px. */
|
|
56
|
+
export declare const SENDER_GAP_PX = 8;
|
|
57
|
+
/** Side gutter of a message row, so a bubble's tail is not clipped, in px. */
|
|
58
|
+
export declare const MESSAGE_ROW_GUTTER_PX = 6;
|
|
45
59
|
export declare const CustomMessageContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
46
60
|
$isUser: boolean;
|
|
47
61
|
$reply: boolean;
|
|
48
|
-
|
|
62
|
+
/** The bubble carries a reaction row that hangs below its bottom edge. */
|
|
63
|
+
$reaction?: boolean;
|
|
64
|
+
/** False when the next message comes from the same sender (a run). */
|
|
65
|
+
$lastInGroup?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* How far the reaction chips hang below the bubble, in px, as measured by
|
|
68
|
+
* MessageReaction (one row is REACTION_HANG_PX). Only used with $reaction.
|
|
69
|
+
*/
|
|
70
|
+
$reactionHang?: number;
|
|
49
71
|
}>> & string;
|
|
72
|
+
/**
|
|
73
|
+
* Visual inset between a bubble's edge and what it holds, in px. A bubble with
|
|
74
|
+
* a 1px border (anyone else's message) takes one px less of padding so the
|
|
75
|
+
* visual inset still matches.
|
|
76
|
+
*
|
|
77
|
+
* Media bubbles (pictures, videos, file cards, voice notes) use 6px on every
|
|
78
|
+
* side, the compact Telegram-style inset that the media block aligns to. Text
|
|
79
|
+
* bubbles use 8px vertical and 12px horizontal.
|
|
80
|
+
*/
|
|
81
|
+
export declare const MEDIA_BUBBLE_INSET_PX = 6;
|
|
82
|
+
export declare const TEXT_BUBBLE_INSET_Y_PX = 8;
|
|
83
|
+
export declare const TEXT_BUBBLE_INSET_X_PX = 12;
|
|
84
|
+
/** Bubble corner radius; media inside it is concentric (radius minus inset). */
|
|
85
|
+
export declare const BUBBLE_RADIUS_PX = 18;
|
|
86
|
+
export declare const MEDIA_RADIUS_PX: number;
|
|
87
|
+
/** Glass time pill over media: how far it sits inside the media edge, in px. */
|
|
88
|
+
export declare const MEDIA_TIME_PILL_OFFSET_PX = 8;
|
|
89
|
+
/** Padding (CSS shorthand value) that yields the visual inset, net of the border. */
|
|
90
|
+
export declare const bubblePadding: (props: {
|
|
91
|
+
$isUser: boolean;
|
|
92
|
+
$deleted: boolean;
|
|
93
|
+
$media?: boolean;
|
|
94
|
+
}) => string;
|
|
95
|
+
/** Corner radius where a tail attaches: the bottom corner on the tail side. */
|
|
96
|
+
export declare const TAIL_CORNER_RADIUS_PX = 4;
|
|
97
|
+
/** Tail box: 10px wide, 12px tall, 6px of it outside the bubble edge. */
|
|
98
|
+
export declare const TAIL_WIDTH_PX = 10;
|
|
99
|
+
export declare const TAIL_HEIGHT_PX = 12;
|
|
50
100
|
export declare const CustomMessageBubble: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
51
101
|
$isUser: boolean;
|
|
52
102
|
$deleted: boolean;
|
|
103
|
+
/** The bubble carries a media block (pictures, videos, cards, voice notes). */
|
|
104
|
+
$media?: boolean;
|
|
105
|
+
/** Its only media is one solo picture or video: the bubble hugs it. */
|
|
106
|
+
$solo?: boolean;
|
|
107
|
+
/** Last of its sender's run, and not a media-only bubble: it gets the tail. */
|
|
108
|
+
$tail?: boolean;
|
|
53
109
|
}>> & string;
|
|
54
110
|
export declare const CustomMessageText: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
55
111
|
export declare const CustomUserName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {
|
|
56
112
|
$isUser: boolean;
|
|
57
113
|
$color?: string;
|
|
114
|
+
/** Inside a media bubble (6px inset): 4px more so it lines up with the caption. */
|
|
115
|
+
$media?: boolean;
|
|
116
|
+
}>> & string;
|
|
117
|
+
export declare const CustomMessageTimestamp: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {
|
|
118
|
+
/** Media bubble: the row sits under the media with 0 8px 4px padding. */
|
|
119
|
+
$media?: boolean;
|
|
120
|
+
/** Text bubble: the time floats at the end of the last line of text. */
|
|
121
|
+
$inline?: boolean;
|
|
122
|
+
/** Glass pill over the media's bottom right corner (media-only bubbles). */
|
|
123
|
+
$overlay?: boolean;
|
|
124
|
+
/** Whether the bubble has its 1px border (it shifts the pill by one px). */
|
|
125
|
+
$bordered?: boolean;
|
|
58
126
|
}>> & string;
|
|
59
|
-
export declare const CustomMessageTimestamp: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
60
127
|
export declare const CustomMessagePhoto: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, never>> & string;
|
|
61
128
|
export declare const CustomMessagePhotoContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
62
129
|
export declare const CustomSystemMessage: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
@@ -1,33 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export declare const
|
|
9
|
-
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Loading spinner rules shared by the media loading states. The spinner is
|
|
4
|
+
* a fixed-pixel circle with `flex: none`, so a flex parent (the upload scrim,
|
|
5
|
+
* a tiny album tile) cannot squash it into an oval. Whether it is drawn at
|
|
6
|
+
* all is decided by a container query on the box it sits in, see below.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MEDIA_SPINNER_PX = 24;
|
|
9
|
+
/** Boxes smaller than this (on either side) get the shimmer only, no spinner. */
|
|
10
|
+
export declare const MEDIA_SPINNER_MIN_BOX_PX = 48;
|
|
11
|
+
export declare const MediaLoadingSkeleton: React.FC<{
|
|
12
|
+
$width?: number;
|
|
13
|
+
$height?: number;
|
|
14
|
+
}>;
|
|
15
|
+
/** Standalone spinner for a loading overlay. Hidden inside boxes under the min size. */
|
|
16
|
+
export declare const MediaSpinner: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
17
|
+
export declare const Container: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
18
|
+
export declare const FullScreenImage: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, never>> & string;
|
|
19
|
+
export declare const ModalContent: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
20
|
+
export declare const ButtonContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
21
|
+
export declare const IconButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
22
|
+
export declare const UnsupportedContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
23
|
+
export declare const BackgroundFile: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
24
|
+
export declare const FileInformation: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
25
|
+
export declare const FileName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
26
|
+
export declare const FileSizeContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
27
|
+
export declare const FileSize: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
16
28
|
/** Wraps every attachment of one message. Single-file messages keep the
|
|
17
29
|
* old, un-gapped look because there is nothing to separate them from. */
|
|
18
|
-
export declare const AttachmentStack: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<
|
|
19
|
-
export declare const AttachmentGrid: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<
|
|
30
|
+
export declare const AttachmentStack: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
31
|
+
export declare const AttachmentGrid: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
20
32
|
$columns: number;
|
|
21
33
|
}>> & string;
|
|
22
|
-
export declare const AttachmentTile: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<
|
|
23
|
-
export declare const PdfContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<
|
|
34
|
+
export declare const AttachmentTile: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
35
|
+
export declare const PdfContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
|
|
24
36
|
$compact: boolean;
|
|
25
37
|
}>> & string;
|
|
26
|
-
export declare const PdfThumbnailFrame: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<
|
|
38
|
+
export declare const PdfThumbnailFrame: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
27
39
|
$compact: boolean;
|
|
28
40
|
}>> & string;
|
|
29
41
|
/** Sits on the thumbnail while pdf.js parses so the row does not pop in. */
|
|
30
|
-
export declare const PdfThumbnailSkeleton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<
|
|
31
|
-
export declare const PdfInformation: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<
|
|
32
|
-
export declare const PdfMetaRow: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<
|
|
33
|
-
export declare const PdfBadge: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<
|
|
42
|
+
export declare const PdfThumbnailSkeleton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
43
|
+
export declare const PdfInformation: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
44
|
+
export declare const PdfMetaRow: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
45
|
+
export declare const PdfBadge: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
/** Full-size player used by the preview modal. Kept here with the bubble video. */
|
|
3
|
+
export declare const FullScreenVideo: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, never>> & string;
|
|
2
4
|
interface CustomMessageVideoProps {
|
|
3
5
|
fileName: string;
|
|
4
6
|
fileURL: string;
|
|
5
7
|
mimetype: string;
|
|
8
|
+
/** Length in seconds, when the attachment recorded one. */
|
|
9
|
+
duration?: string;
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
6
12
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export declare const IconButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
13
|
+
/**
|
|
14
|
+
* A single video in a bubble: the first frame with a glass play button and,
|
|
15
|
+
* when known, a duration chip. A click opens the preview modal, which holds
|
|
16
|
+
* the controls.
|
|
17
|
+
*/
|
|
13
18
|
declare const CustomMessageVideo: React.FC<CustomMessageVideoProps>;
|
|
14
19
|
export default CustomMessageVideo;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Element } from 'ltx';
|
|
2
|
+
/** Namespace of the <call-key> signal element carried inside the SCE envelope. */
|
|
3
|
+
export declare const NS_CALL_E2EE = "ethora:call:e2ee:0";
|
|
4
|
+
/**
|
|
5
|
+
* A fresh 256-bit media key for one call, as a base64 string. A new key per
|
|
6
|
+
* call gives forward secrecy between calls: a key recovered from one call
|
|
7
|
+
* cannot open the next. The string is fed verbatim to both peers'
|
|
8
|
+
* `ExternalE2EEKeyProvider.setKey`, which HKDFs it into the frame key.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateCallKey(): string;
|
|
11
|
+
/** The <call-key> element that rides inside the OMEMO SCE envelope. */
|
|
12
|
+
export declare function callKeyElement(callId: string, key: string): Element;
|
|
13
|
+
/**
|
|
14
|
+
* Hands `key` to every member of `roomJid`, end-to-end encrypted via OMEMO so
|
|
15
|
+
* the server never sees it.
|
|
16
|
+
*
|
|
17
|
+
* Returns false (a no-op) unless E2EE is enabled for the app AND the backend
|
|
18
|
+
* marked the room `e2ee`, or when no member has published an OMEMO device yet
|
|
19
|
+
* (in which case the caller falls back to a non-E2EE call rather than
|
|
20
|
+
* failing). Returns true once the encrypted key is on its way to at least one
|
|
21
|
+
* recipient device.
|
|
22
|
+
*/
|
|
23
|
+
export declare function distributeCallKey(roomJid: string, callId: string, key: string): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* Reads a decrypted <call-key> off a stanza the OMEMO seam has already
|
|
26
|
+
* rewritten in place (so the element sits as an ordinary child). Returns
|
|
27
|
+
* undefined when the stanza is not a call-key signal.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseCallKey(stanza: Element): {
|
|
30
|
+
callId: string;
|
|
31
|
+
key: string;
|
|
32
|
+
} | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IMentionSpan } from '../types/types';
|
|
1
2
|
/** What the server must not learn, and the receiver needs to render. */
|
|
2
3
|
export interface FileEnvelopeMeta {
|
|
3
4
|
mimetype: string;
|
|
@@ -37,12 +38,22 @@ export declare function openSealedFile(ciphertext: Uint8Array, keyMaterial: stri
|
|
|
37
38
|
meta: FileEnvelopeMeta;
|
|
38
39
|
bytes: Uint8Array;
|
|
39
40
|
};
|
|
41
|
+
/** What a sealed media <body> carries besides the keys. */
|
|
42
|
+
export interface SealedMediaPayload {
|
|
43
|
+
keys: string[];
|
|
44
|
+
/** The text typed with the files. Sealed here, never on <data>. */
|
|
45
|
+
caption?: string;
|
|
46
|
+
captionMentions?: IMentionSpan[];
|
|
47
|
+
}
|
|
40
48
|
/**
|
|
41
|
-
* Pull the attachment keys out of a
|
|
49
|
+
* Pull the attachment keys (and the caption, when there is one) out of a
|
|
50
|
+
* decrypted media <body>.
|
|
42
51
|
*
|
|
43
|
-
* The sender put `{v:1,keys:[...]}` there instead of
|
|
44
|
-
* "media" (see sendMediaMessage). Returns undefined for
|
|
45
|
-
* an ordinary media message - or one from a build that
|
|
46
|
-
* falls through untouched.
|
|
52
|
+
* The sender put `{v:1,keys:[...],caption?,captionMentions?}` there instead of
|
|
53
|
+
* the usual literal "media" (see sendMediaMessage). Returns undefined for
|
|
54
|
+
* anything else, so an ordinary media message - or one from a build that
|
|
55
|
+
* predates sealing - falls through untouched.
|
|
47
56
|
*/
|
|
57
|
+
export declare function parseSealedMediaPayload(body?: string): SealedMediaPayload | undefined;
|
|
58
|
+
/** The attachment keys out of a sealed media <body>; see parseSealedMediaPayload. */
|
|
48
59
|
export declare function parseSealedMediaBody(body?: string): string[] | undefined;
|
package/dist/e2ee/omemo.d.ts
CHANGED
|
@@ -105,6 +105,24 @@ export declare class Omemo {
|
|
|
105
105
|
* the room's echo by it.
|
|
106
106
|
*/
|
|
107
107
|
encryptGroupMessage(roomJid: string, members: string[], content: Element[], id: string, cleartext?: Element[]): Promise<Element>;
|
|
108
|
+
/**
|
|
109
|
+
* Sends an ephemeral, end-to-end encrypted control signal to a room's
|
|
110
|
+
* members. Same OMEMO envelope as `encryptGroupMessage`, but it is NOT a
|
|
111
|
+
* chat message: no fallback <body>, no <store> hint, and MAM/carbons are
|
|
112
|
+
* asked to drop it (`no-store` / `no-permanent-store` / `no-copy`).
|
|
113
|
+
*
|
|
114
|
+
* The use case is handing a LiveKit call's media key to the other
|
|
115
|
+
* participants without the server - or anyone relaying the stanza - ever
|
|
116
|
+
* seeing it. The payload rides inside the SCE envelope exactly like a
|
|
117
|
+
* message body would, so the server observes ciphertext only.
|
|
118
|
+
*
|
|
119
|
+
* Returns true when at least one recipient device was reachable (so the
|
|
120
|
+
* caller knows the key actually went out), false when nobody in the room
|
|
121
|
+
* has published an OMEMO device yet. Unlike `encryptGroupMessage` it does
|
|
122
|
+
* not throw on an empty recipient set: a call simply falls back to plaintext
|
|
123
|
+
* media rather than failing, and the caller decides what to surface.
|
|
124
|
+
*/
|
|
125
|
+
sendGroupSignal(roomJid: string, members: string[], content: Element[], id: string): Promise<boolean>;
|
|
108
126
|
/**
|
|
109
127
|
* Empty OMEMO message: completes a session the peer started. It targets one
|
|
110
128
|
* device, so it goes straight to that member's real JID rather than through
|
|
@@ -151,8 +151,25 @@ async function checkAssetAvailability(url) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
// `<appId>_<userId>` (24-hex ids, or an appId and a uuid) is a machine id,
|
|
155
|
+
// never something to put in a notification title.
|
|
156
|
+
const OPAQUE_ID_RE =
|
|
157
|
+
/^(?:[0-9a-f]{24}(?:_[0-9a-f]{24})?|[a-z0-9]+_(?:[0-9a-f]{24}|[0-9a-f-]{36})(?:_[0-9a-z-]+)*)$/i;
|
|
158
|
+
|
|
159
|
+
function isOpaqueId(value) {
|
|
160
|
+
const text = String(value || '').trim();
|
|
161
|
+
return !!text && OPAQUE_ID_RE.test(text.split('@')[0]);
|
|
162
|
+
}
|
|
163
|
+
|
|
154
164
|
function pickTitle(raw = {}, data = {}, notification = {}) {
|
|
155
|
-
|
|
165
|
+
const title = notification.title || raw.title || data.title || '';
|
|
166
|
+
return title && !isOpaqueId(title) ? title : 'New Message';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// One notification per chat: a newer message in the same room replaces it.
|
|
170
|
+
function roomTag(data = {}) {
|
|
171
|
+
const jid = String(data.jid || '').split('@')[0];
|
|
172
|
+
return jid ? `ethora-room-${jid}` : '';
|
|
156
173
|
}
|
|
157
174
|
|
|
158
175
|
function pickBody(raw = {}, data = {}, notification = {}) {
|
|
@@ -449,8 +466,8 @@ async function handlePush(raw = {}, source = 'push') {
|
|
|
449
466
|
icon,
|
|
450
467
|
badge,
|
|
451
468
|
image,
|
|
452
|
-
tag: isCall ? `call:${callId || dedupKey}` : dedupKey,
|
|
453
|
-
renotify: isCall,
|
|
469
|
+
tag: isCall ? `call:${callId || dedupKey}` : roomTag(data) || dedupKey,
|
|
470
|
+
renotify: isCall || !!roomTag(data),
|
|
454
471
|
requireInteraction: isCall,
|
|
455
472
|
// Spread the ORIGINAL payload first so the click handler's isCallPush()
|
|
456
473
|
// sees the full call fields (callId/callToken/kind/room); our routing
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geometry for a multi-media album bubble. Pure data so the grid component
|
|
3
|
+
* stays a dumb renderer and the layout rules can be tested without a DOM.
|
|
4
|
+
*
|
|
5
|
+
* 1 item full width, 4:3
|
|
6
|
+
* 2 items side by side, square cells
|
|
7
|
+
* 3 items one large cell on the left, two stacked on the right
|
|
8
|
+
* 4 items 2 x 2
|
|
9
|
+
* 5+ items 2 x 2 showing the first four, the last cell carries "+N"
|
|
10
|
+
*/
|
|
11
|
+
/** Gap between neighbouring tiles. */
|
|
12
|
+
export declare const ALBUM_GAP_PX = 3;
|
|
13
|
+
/** Radius of a tile corner that sits on the bubble's own corner. */
|
|
14
|
+
export declare const ALBUM_OUTER_RADIUS_PX = 12;
|
|
15
|
+
/** Radius of every other tile corner, the ones that face a neighbour. */
|
|
16
|
+
export declare const ALBUM_INNER_RADIUS_PX = 3;
|
|
17
|
+
export interface AlbumCellPlacement {
|
|
18
|
+
/** CSS `grid-column` value. */
|
|
19
|
+
column: string;
|
|
20
|
+
/** CSS `grid-row` value. */
|
|
21
|
+
row: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AlbumLayout {
|
|
24
|
+
kind: 'full' | 'pair' | 'hero' | 'quad';
|
|
25
|
+
/** Number of tiles actually drawn. */
|
|
26
|
+
visible: number;
|
|
27
|
+
/** Items folded into the "+N" overlay on the last visible tile. */
|
|
28
|
+
hidden: number;
|
|
29
|
+
/** CSS `grid-template-columns`. */
|
|
30
|
+
columns: string;
|
|
31
|
+
/** CSS `grid-template-rows`. */
|
|
32
|
+
rows: string;
|
|
33
|
+
/** CSS `aspect-ratio` of the whole grid. */
|
|
34
|
+
aspectRatio: string;
|
|
35
|
+
/** One entry per visible tile, in order. */
|
|
36
|
+
placements: AlbumCellPlacement[];
|
|
37
|
+
}
|
|
38
|
+
/** Layout for `count` media tiles. Counts below 1 are treated as 1. */
|
|
39
|
+
export declare const getAlbumLayout: (count: number) => AlbumLayout;
|
|
40
|
+
/**
|
|
41
|
+
* Which corners of one tile lie on the bubble's outer edge. Only those get
|
|
42
|
+
* the large radius; corners that face a neighbour get the small inner one.
|
|
43
|
+
*/
|
|
44
|
+
export interface TileCorners {
|
|
45
|
+
topLeft: boolean;
|
|
46
|
+
topRight: boolean;
|
|
47
|
+
bottomRight: boolean;
|
|
48
|
+
bottomLeft: boolean;
|
|
49
|
+
}
|
|
50
|
+
/** Outer-corner flags for the tile at `position` (0-based) of `layout`. */
|
|
51
|
+
export declare const getTileCorners: (layout: AlbumLayout, position: number) => TileCorners;
|
|
52
|
+
/** CSS `border-radius` shorthand (TL TR BR BL) for one tile. */
|
|
53
|
+
export declare const getTileBorderRadius: (layout: AlbumLayout, position: number) => string;
|