@ethora/chat-component 26.7.6 → 26.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ChatProfileModal-DehQM4Bo.js +2135 -0
- package/dist/FilePreviewModal-BcZLtVAy.js +743 -0
- package/dist/{ManageDataModal-CDPXcC93.js → ManageDataModal-DWabKhSC.js} +68 -49
- package/dist/{MarkdownBody-DBJGraWM.js → MarkdownBody-CSY3YKDh.js} +1 -1
- package/dist/{SideDrawer-Dr_lkaOW.js → SideDrawer-DewJ-iPn.js} +110 -66
- package/dist/UserProfileModal-BHZ0TULc.js +574 -0
- package/dist/{UserSettingsModal-OcAJao-d.js → UserSettingsModal-BxwVWNKo.js} +2 -2
- package/dist/{VideoCallOverlay-CC4sShdK.js → VideoCallOverlay-D5SuimGP.js} +1 -1
- package/dist/{VisibilityModal-DkMhx_2k.js → VisibilityModal-Bd67b4EM.js} +2 -2
- package/dist/components/MainComponents/ChatRoomOpeningPreview.d.ts +24 -0
- package/dist/components/MainComponents/ChatWrapper.d.ts +1 -0
- package/dist/components/MainComponents/ChooseChatMessage.d.ts +11 -1
- package/dist/components/Modals/Modal/Modal.d.ts +10 -0
- package/dist/components/Modals/Modal/ModalContent.d.ts +21 -0
- package/dist/components/Modals/ModalBox/ModalBox.d.ts +9 -0
- package/dist/components/Modals/ModalReportChat/ModalReportChat.d.ts +6 -1
- package/dist/components/Modals/ModalWrapper/ModalWrapper.d.ts +8 -0
- package/dist/components/Modals/SettingsModals/SharedStyledComponents.d.ts +12 -0
- package/dist/components/Modals/SideDrawer/DrawerProfileParts.d.ts +29 -0
- package/dist/components/Modals/SideDrawer/SideDrawer.d.ts +21 -1
- package/dist/components/Modals/SidePanel/SidePanel.d.ts +31 -0
- package/dist/components/Modals/UserProfileModal/EditUserModal.d.ts +5 -1
- package/dist/components/Modals/motionVariants.d.ts +37 -0
- package/dist/components/Modals/styledModalComponents.d.ts +0 -1
- package/dist/context/ModalTransitionContext.d.ts +2 -0
- package/dist/handleCopyClick-BoZWTBLC.js +108 -0
- package/dist/helpers/buildChatShareLink.d.ts +20 -0
- package/dist/helpers/cacheScope.d.ts +15 -1
- package/dist/helpers/constants/MODAL_TYPES.d.ts +6 -4
- package/dist/helpers/createRoomFromApi.d.ts +1 -1
- package/dist/helpers/formatNumberWithCommas.d.ts +1 -1
- package/dist/hooks/useChatOpenPhase.d.ts +21 -0
- package/dist/hooks/useDelayedAction.d.ts +22 -0
- package/dist/hooks/useExclusiveRightPane.d.ts +25 -0
- package/dist/hooks/useExitTransition.d.ts +24 -0
- package/dist/hooks/useGetNewArchRoom.d.ts +3 -1
- package/dist/hooks/useQRCodeChatHandler.d.ts +29 -1
- package/dist/{main-B-8IhwaP.js → main-C2FKeV6y.js} +8107 -7569
- package/dist/main.css +1 -1
- package/dist/main.js +5 -5
- package/dist/styles/motion.d.ts +27 -0
- package/dist/types/models/room.model.d.ts +28 -0
- package/package.json +1 -1
- package/dist/ChatProfileModal-hxsWI8cx.js +0 -2139
- package/dist/FilePreviewModal-CwWnHsB1.js +0 -736
- package/dist/UserProfileModal-Q_jhXpsX.js +0 -568
- package/dist/handleCopyClick-CpmPa6VI.js +0 -32
|
@@ -3,6 +3,15 @@ interface ModalBoxProps {
|
|
|
3
3
|
title: string;
|
|
4
4
|
handleCloseModal: () => void;
|
|
5
5
|
children: ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* True while the caller is keeping this mounted only to let the exit
|
|
8
|
+
* animation finish (see `useExitTransition` at the call site - typically
|
|
9
|
+
* `{shouldRender && <ModalBox isClosing={isExiting} .../>}`). Every close
|
|
10
|
+
* trigger here (X button, Escape, outside click) still just calls
|
|
11
|
+
* `handleCloseModal` immediately: the caller decides how long to keep
|
|
12
|
+
* rendering, this component only decides how it looks while that happens.
|
|
13
|
+
*/
|
|
14
|
+
isClosing?: boolean;
|
|
6
15
|
}
|
|
7
16
|
export declare const ModalBox: FC<ModalBoxProps>;
|
|
8
17
|
export {};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { default as React, FC } from 'react';
|
|
2
2
|
export declare const Report: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
3
|
-
|
|
3
|
+
interface ModalReportChatProps {
|
|
4
|
+
/** Forwarded to `ModalBox` - see its `isClosing` doc. */
|
|
5
|
+
isClosing?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const ModalReportChat: FC<ModalReportChatProps>;
|
|
8
|
+
export {};
|
|
@@ -11,6 +11,14 @@ interface ModalWrapperProps {
|
|
|
11
11
|
setTextarea?: (value: string) => void;
|
|
12
12
|
handleCloseModal: () => void;
|
|
13
13
|
handleClick: () => void;
|
|
14
|
+
/**
|
|
15
|
+
* True while the caller is keeping this mounted only so the exit
|
|
16
|
+
* animation can finish - see `ModalBox`'s `isClosing` doc for the pattern
|
|
17
|
+
* (a `useExitTransition` at the `{shouldRender && <ModalWrapper .../>}`
|
|
18
|
+
* call site). Buttons here still call `handleCloseModal`/`handleClick`
|
|
19
|
+
* immediately either way.
|
|
20
|
+
*/
|
|
21
|
+
isClosing?: boolean;
|
|
14
22
|
}
|
|
15
23
|
export declare const ModalWrapper: FC<ModalWrapperProps>;
|
|
16
24
|
export {};
|
|
@@ -11,11 +11,23 @@ export declare const RowWrapper: import('styled-components/dist/types').IStyledC
|
|
|
11
11
|
export declare const SharedSettingsLabelData: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<Omit<import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>, "ref"> & {
|
|
12
12
|
ref?: import('react').Ref<HTMLSpanElement>;
|
|
13
13
|
}, never>> & string;
|
|
14
|
+
/**
|
|
15
|
+
* A settings action rendered as its own outlined row rather than an inline
|
|
16
|
+
* link, so "download my data" / "delete my account" read as deliberate,
|
|
17
|
+
* separately-weighted decisions - not just more text in the card. The
|
|
18
|
+
* border colour is caller-driven (primary for a normal action, the danger
|
|
19
|
+
* token for the destructive one), everything else - radius, padding,
|
|
20
|
+
* weight, the hover/focus feedback - comes from the shared tokens so both
|
|
21
|
+
* read as the same kind of control.
|
|
22
|
+
*/
|
|
14
23
|
export declare const SharedSettingsStyledButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<Omit<ButtonProps & import('react').RefAttributes<HTMLButtonElement>, "ref"> & {
|
|
15
24
|
ref?: import('react').Ref<HTMLButtonElement>;
|
|
16
25
|
}, {
|
|
17
26
|
borderColor: string;
|
|
18
27
|
}>> & string & Omit<import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLButtonElement>>, keyof import('react').Component<any, {}, any>>;
|
|
28
|
+
/** A quiet, boxed disclosure - the read-only counterpart to the button
|
|
29
|
+
* above, so a fact ("your data may be retained on-chain") doesn't compete
|
|
30
|
+
* visually with an action the person can take. */
|
|
19
31
|
export declare const SharedSettingsInfoPanel: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
20
32
|
bgColor: string;
|
|
21
33
|
}>> & string;
|
|
@@ -7,7 +7,36 @@
|
|
|
7
7
|
* the same shape.
|
|
8
8
|
*/
|
|
9
9
|
export declare const ProfileHero: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
10
|
+
/**
|
|
11
|
+
* The one bold, largest line in the entire panel family: deliberately so.
|
|
12
|
+
* Everything else in these drawers tops out at semibold (section labels,
|
|
13
|
+
* header title, row labels), so this is the only place `font-weight-bold`
|
|
14
|
+
* is used - it is what makes the hero read as the peak of the hierarchy
|
|
15
|
+
* instead of just another slightly-bigger label.
|
|
16
|
+
*/
|
|
10
17
|
export declare const ProfileHeroName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
11
18
|
export declare const ProfileHeroSubtitle: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
12
19
|
/** Stack of full-width action buttons, one per row. */
|
|
13
20
|
export declare const ProfileActions: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
21
|
+
/**
|
|
22
|
+
* Room/profile description, set directly under the hero with no "Description"
|
|
23
|
+
* label above it - the About section heading already says what this is.
|
|
24
|
+
* When there is no description yet, `$empty` swaps in a muted italic tone so
|
|
25
|
+
* the placeholder line reads as an unwritten blank rather than a failed
|
|
26
|
+
* value, without changing the copy or the layout.
|
|
27
|
+
*/
|
|
28
|
+
export declare const DrawerDescriptionText: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, {
|
|
29
|
+
$empty?: boolean;
|
|
30
|
+
}>> & string;
|
|
31
|
+
/** Small icon+label tag for a single fact (chat type, visibility, ...). */
|
|
32
|
+
export declare const DrawerFactPill: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
33
|
+
/**
|
|
34
|
+
* A deliberate blank state - icon, title, optional hint - for "nothing here
|
|
35
|
+
* yet" spots (no files, no members) that used to be a single line of grey
|
|
36
|
+
* text sitting in a box and reading like something had gone wrong.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DrawerEmptyState: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
39
|
+
$compact?: boolean;
|
|
40
|
+
}>> & string;
|
|
41
|
+
export declare const DrawerEmptyStateTitle: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
42
|
+
export declare const DrawerEmptyStateHint: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { FC, ReactNode } from 'react';
|
|
2
|
-
export declare const DrawerPanel: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').
|
|
2
|
+
export declare const DrawerPanel: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
3
|
+
$closing?: boolean;
|
|
4
|
+
}>> & string;
|
|
3
5
|
/** A labelled group: small caps heading, then a bordered card of rows. */
|
|
4
6
|
export declare const DrawerSection: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLElement>, HTMLElement>, never>> & string;
|
|
5
7
|
export declare const DrawerSectionTitle: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, never>> & string;
|
|
@@ -17,6 +19,24 @@ export declare const SectionHeaderRow: import('styled-components/dist/types').IS
|
|
|
17
19
|
export declare const ShowMoreButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
18
20
|
/** Hairline between two rows of the same card. */
|
|
19
21
|
export declare const DrawerRowDivider: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
22
|
+
/**
|
|
23
|
+
* Filled, borderless search field - matches the room list's and the Files
|
|
24
|
+
* tab's own search bars (bg-subtle fill, no border) rather than the boxed,
|
|
25
|
+
* bordered field the member search used to be, which sat inside a bordered
|
|
26
|
+
* `DrawerCard` and read as a box nested in another box. Not built on the
|
|
27
|
+
* shared `InputComponents/Search` component: that one adds its own visible
|
|
28
|
+
* border and isn't in this pass's file list, so this is a local, purpose-fit
|
|
29
|
+
* equivalent that shares the same visual language as the other search bars
|
|
30
|
+
* in the app.
|
|
31
|
+
*/
|
|
32
|
+
export declare const DrawerSearchBar: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
33
|
+
export declare const DrawerSearchInput: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, never>> & string;
|
|
34
|
+
/**
|
|
35
|
+
* Flat row list with no surrounding card border - used where the rows
|
|
36
|
+
* themselves (via hover/press state) already read as one group, e.g. the
|
|
37
|
+
* member list, so it doesn't also need a bounding box drawn around it.
|
|
38
|
+
*/
|
|
39
|
+
export declare const DrawerList: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
20
40
|
export declare const DrawerLabel: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
21
41
|
export declare const DrawerHint: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
22
42
|
interface DrawerNavRowProps {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { ModalType } from '../../../types/types';
|
|
3
|
+
/**
|
|
4
|
+
* The chat's third column: chat profile, user profile, settings, Manage Data
|
|
5
|
+
* and Visibility.
|
|
6
|
+
*
|
|
7
|
+
* These used to be children of the modal overlay layer - a fixed,
|
|
8
|
+
* full-viewport `ModalBackground` with the panel parked against its right
|
|
9
|
+
* edge - so opening one dropped a 400px panel ON TOP of the conversation and
|
|
10
|
+
* the message you were reading disappeared underneath it. This component is
|
|
11
|
+
* rendered as a sibling of the chat pane inside `ChatWrapper`'s flex row
|
|
12
|
+
* instead, so the panel occupies real layout space and the chat simply gets
|
|
13
|
+
* narrower, the way Telegram Web behaves.
|
|
14
|
+
*
|
|
15
|
+
* Which panel is open is still the store's `activeModal` and is still routed
|
|
16
|
+
* through `MODAL_COMPONENTS`; `ModalContent` is the shared router both this
|
|
17
|
+
* and `Modal` use, so there is exactly one source of truth.
|
|
18
|
+
*
|
|
19
|
+
* Below the mobile breakpoint the column goes back to covering everything:
|
|
20
|
+
* three columns cannot fit on a phone, and the panel being the whole screen
|
|
21
|
+
* is the behaviour that was already there. `ChatWrapperInnerBox` is
|
|
22
|
+
* positioned, so `inset: 0` here is the chat's own box, not the host page.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SIDE_PANEL_WIDTH_PX = 400;
|
|
25
|
+
export declare const SIDE_PANEL_BREAKPOINT_PX = 767;
|
|
26
|
+
interface SidePanelProps {
|
|
27
|
+
modal?: string;
|
|
28
|
+
setOpenModal: (value?: ModalType) => any;
|
|
29
|
+
}
|
|
30
|
+
declare const SidePanel: React.FC<SidePanelProps>;
|
|
31
|
+
export default SidePanel;
|
|
@@ -4,5 +4,9 @@ interface EditUserModalProps {
|
|
|
4
4
|
modalUser: any;
|
|
5
5
|
config: any;
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
/** What the parent drawer's header Save button calls. */
|
|
8
|
+
export interface EditUserModalHandle {
|
|
9
|
+
save: () => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
declare const EditUserModal: React.ForwardRefExoticComponent<EditUserModalProps & React.RefAttributes<EditUserModalHandle>>;
|
|
8
12
|
export default EditUserModal;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit-animation variants of the shared modal primitives from
|
|
3
|
+
* `styledModalComponents.tsx` (owned by another agent right now - see
|
|
4
|
+
* CLAUDE.md coordination notes, not edited here). `styled(Component)`
|
|
5
|
+
* composition lets these add a `$closing` branch without touching that
|
|
6
|
+
* file: styled-components injects the extending component's class after the
|
|
7
|
+
* base one, so its rules win the cascade for the same element.
|
|
8
|
+
*
|
|
9
|
+
* Used by `Modal.tsx`, `NewChatModal.tsx` and `ModalWrapper.tsx` to fade/
|
|
10
|
+
* scale a modal out instead of letting it vanish when it unmounts.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* `$closing` fades the scrim back out.
|
|
14
|
+
*
|
|
15
|
+
* This used to skip the fade in the backdrop's old `$drawer` mode, where the
|
|
16
|
+
* scrim was transparent and had nothing to fade. That mode is gone: the
|
|
17
|
+
* profile and settings panels are a layout column now (see SidePanel), so the
|
|
18
|
+
* only things left behind this backdrop are real centred dialogs, and they all
|
|
19
|
+
* want the fade.
|
|
20
|
+
*/
|
|
21
|
+
export declare const PresenceModalBackground: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<Omit<import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "$anchorTop"> & {
|
|
22
|
+
$anchorTop?: boolean;
|
|
23
|
+
}, "ref"> & {
|
|
24
|
+
ref?: import('react').Ref<HTMLDivElement>;
|
|
25
|
+
}, {
|
|
26
|
+
$closing?: boolean;
|
|
27
|
+
}>> & string;
|
|
28
|
+
export declare const PresenceModalContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('styled-components').FastOmit<import('styled-components').FastOmit<import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
29
|
+
ref?: import('react').Ref<HTMLDivElement>;
|
|
30
|
+
}>, never>, never>, {
|
|
31
|
+
$closing?: boolean;
|
|
32
|
+
}>> & string;
|
|
33
|
+
export declare const PresenceModalContainerFullScreen: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('styled-components').FastOmit<import('styled-components').FastOmit<import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
34
|
+
ref?: import('react').Ref<HTMLDivElement>;
|
|
35
|
+
}>, never>, never>, {
|
|
36
|
+
$closing?: boolean;
|
|
37
|
+
}>> & string;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ButtonProps } from '../styled/Button';
|
|
2
2
|
export declare const ModalBackground: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
3
3
|
$anchorTop?: boolean;
|
|
4
|
-
$drawer?: boolean;
|
|
5
4
|
}>> & string;
|
|
6
5
|
export declare const CloseButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('react').DetailedHTMLProps<import('react').ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
7
6
|
export declare const ModalContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<import('styled-components').FastOmit<import('styled-components/dist/types').Substitute<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { v as e, x as t } from "./main-C2FKeV6y.js";
|
|
2
|
+
const i = e.div`
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: var(--ethora-space-4, 16px);
|
|
7
|
+
padding: var(--ethora-space-3, 12px) 0 var(--ethora-space-2, 8px);
|
|
8
|
+
text-align: center;
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* The avatar (ProfileImagePlaceholder) is always this block's first and
|
|
12
|
+
* only non-text child - both callers (ChatProfileModal, UserProfileModal)
|
|
13
|
+
* render it first, before the name. A soft ring around it - the panel's
|
|
14
|
+
* own background colour, then the same elevation a card gets - lifts it
|
|
15
|
+
* off the page as the one deliberately-composed focal point instead of a
|
|
16
|
+
* flat circle sitting in a vertical stack. Targeting the position (not a
|
|
17
|
+
* class) means this works without touching ProfileImagePlaceholder itself,
|
|
18
|
+
* which is outside this pass's file list.
|
|
19
|
+
*/
|
|
20
|
+
& > *:first-child {
|
|
21
|
+
box-shadow:
|
|
22
|
+
0 0 0 4px var(--ethora-color-bg, #fff),
|
|
23
|
+
var(--ethora-shadow-md, 0 4px 12px rgba(16, 24, 40, 0.1));
|
|
24
|
+
border-radius: var(--ethora-radius-full, 999px);
|
|
25
|
+
}
|
|
26
|
+
`, s = e.div`
|
|
27
|
+
font-size: var(--ethora-font-size-xl, 22px);
|
|
28
|
+
font-weight: var(--ethora-font-weight-bold, 700);
|
|
29
|
+
line-height: var(--ethora-line-height-tight, 1.25);
|
|
30
|
+
color: var(--ethora-color-text, #141414);
|
|
31
|
+
overflow-wrap: anywhere;
|
|
32
|
+
`, l = e.div`
|
|
33
|
+
margin-top: var(--ethora-space-1, 4px);
|
|
34
|
+
font-size: var(--ethora-font-size-sm, 14px);
|
|
35
|
+
font-weight: var(--ethora-font-weight-medium, 500);
|
|
36
|
+
color: var(--ethora-color-text-muted, #8c8c8c);
|
|
37
|
+
`, n = e.div`
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
gap: var(--ethora-space-2, 8px);
|
|
41
|
+
width: 100%;
|
|
42
|
+
margin-top: var(--ethora-space-1, 4px);
|
|
43
|
+
`, c = e.p`
|
|
44
|
+
margin: 0;
|
|
45
|
+
font-size: var(--ethora-font-size-sm, 14px);
|
|
46
|
+
line-height: var(--ethora-line-height-normal, 1.5);
|
|
47
|
+
color: ${({ $empty: a }) => a ? "var(--ethora-color-text-muted, #8c8c8c)" : "var(--ethora-color-text, #141414)"};
|
|
48
|
+
font-style: ${({ $empty: a }) => a ? "italic" : "normal"};
|
|
49
|
+
text-align: start;
|
|
50
|
+
overflow-wrap: anywhere;
|
|
51
|
+
`, h = e.span`
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
/* The pill is usually a child of a column flex container, which blockifies
|
|
54
|
+
inline-flex and stretches it to the full column width unless it opts out.
|
|
55
|
+
A pill that spans the whole panel reads as a banner, not as a tag. */
|
|
56
|
+
align-self: flex-start;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: var(--ethora-space-1, 4px);
|
|
59
|
+
padding: var(--ethora-space-1, 4px) var(--ethora-space-3, 12px);
|
|
60
|
+
border-radius: var(--ethora-radius-full, 999px);
|
|
61
|
+
background: var(--ethora-color-primary-soft, #e7edf9);
|
|
62
|
+
color: var(--ethora-color-primary, #0052cd);
|
|
63
|
+
font-size: var(--ethora-font-size-xs, 12px);
|
|
64
|
+
font-weight: var(--ethora-font-weight-semibold, 600);
|
|
65
|
+
|
|
66
|
+
& > svg {
|
|
67
|
+
width: 14px;
|
|
68
|
+
height: 14px;
|
|
69
|
+
}
|
|
70
|
+
`, o = t`
|
|
71
|
+
padding: ${({ $compact: a }) => a ? "var(--ethora-space-4, 16px) var(--ethora-space-2, 8px)" : "var(--ethora-space-6, 24px) var(--ethora-space-4, 16px)"};
|
|
72
|
+
`, p = e.div`
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
text-align: center;
|
|
78
|
+
gap: var(--ethora-space-1, 4px);
|
|
79
|
+
color: var(--ethora-color-text-secondary, #5a5f66);
|
|
80
|
+
${o}
|
|
81
|
+
|
|
82
|
+
& > svg {
|
|
83
|
+
opacity: 0.7;
|
|
84
|
+
margin-bottom: var(--ethora-space-1, 4px);
|
|
85
|
+
}
|
|
86
|
+
`, f = e.div`
|
|
87
|
+
font-size: var(--ethora-font-size-sm, 14px);
|
|
88
|
+
font-weight: var(--ethora-font-weight-medium, 500);
|
|
89
|
+
color: var(--ethora-color-text-secondary, #5a5f66);
|
|
90
|
+
`;
|
|
91
|
+
e.div`
|
|
92
|
+
font-size: var(--ethora-font-size-xs, 12px);
|
|
93
|
+
color: var(--ethora-color-text-muted, #8c8c8c);
|
|
94
|
+
`;
|
|
95
|
+
const d = (a) => {
|
|
96
|
+
navigator.clipboard.writeText(a);
|
|
97
|
+
};
|
|
98
|
+
export {
|
|
99
|
+
c as D,
|
|
100
|
+
i as P,
|
|
101
|
+
s as a,
|
|
102
|
+
n as b,
|
|
103
|
+
l as c,
|
|
104
|
+
h as d,
|
|
105
|
+
p as e,
|
|
106
|
+
f,
|
|
107
|
+
d as h
|
|
108
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the "open this chat" link that the QR modal encodes.
|
|
3
|
+
*
|
|
4
|
+
* Two rules matter here:
|
|
5
|
+
*
|
|
6
|
+
* 1. The link has to point back at a page that actually mounts <Chat>.
|
|
7
|
+
* The old fallback invented a `/app/chat/` path from the current origin
|
|
8
|
+
* (and, with no window, an even older `beta.ethora.com` build-time URL),
|
|
9
|
+
* so scanning the QR on any deployment whose chat does not live at
|
|
10
|
+
* `/app/chat/` landed on a blank page. The current page is the one the
|
|
11
|
+
* user is looking at the chat in, so its own origin + pathname is the
|
|
12
|
+
* only entry point we can honestly guarantee. A host that serves chat
|
|
13
|
+
* somewhere else still overrides everything via `config.qrUrl`.
|
|
14
|
+
*
|
|
15
|
+
* 2. The parameter is written with URLSearchParams so an existing query
|
|
16
|
+
* string on the page (locale switches, host params) survives instead of
|
|
17
|
+
* being clobbered, and the id is encoded.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CHAT_LINK_PARAM = "chatId";
|
|
20
|
+
export declare const buildChatShareLink: (chatJid: string, qrUrl?: string, currentHref?: string) => string;
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { IConfig } from '../types/types';
|
|
2
2
|
export declare const buildCacheScope: (config?: IConfig) => string;
|
|
3
|
-
|
|
3
|
+
interface ClearScopedChatCacheOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Keep the chat id a QR code / shared link just parked.
|
|
6
|
+
*
|
|
7
|
+
* That id is not cached data from a previous session, it is the room the
|
|
8
|
+
* user is arriving at RIGHT NOW. Wiping it on a first-run reset (which is
|
|
9
|
+
* exactly when someone opens a link on a fresh browser) dropped the
|
|
10
|
+
* destination on the floor: the selection was cleared, and the first room
|
|
11
|
+
* that happened to arrive over XMPP was opened instead. A genuine tenant
|
|
12
|
+
* switch still drops it - a bare chat id means nothing in another tenant.
|
|
13
|
+
*/
|
|
14
|
+
keepPendingChatId?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const clearScopedChatCache: (options?: ClearScopedChatCacheOptions) => void;
|
|
4
17
|
export declare const ensureScopedChatCache: (config?: IConfig) => {
|
|
5
18
|
changed: boolean;
|
|
6
19
|
scope: string;
|
|
7
20
|
previousScope: string | null;
|
|
8
21
|
};
|
|
22
|
+
export {};
|
|
@@ -12,8 +12,10 @@ export declare const MODAL_TYPES: {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const SETTINGS_SUB_MODAL_TYPES: string[];
|
|
14
14
|
/**
|
|
15
|
-
* Panels that open as
|
|
16
|
-
* the profile/settings family.
|
|
17
|
-
*
|
|
15
|
+
* Panels that open as the chat's right-hand COLUMN rather than as a centred
|
|
16
|
+
* card on top of it: the profile/settings family. These take part in the
|
|
17
|
+
* layout (see `components/Modals/SidePanel/SidePanel.tsx`), so opening one
|
|
18
|
+
* narrows the conversation instead of covering it. Everything else (file
|
|
19
|
+
* preview and the confirm dialogs) keeps the centred-dialog presentation.
|
|
18
20
|
*/
|
|
19
|
-
export declare const
|
|
21
|
+
export declare const SIDE_PANEL_MODAL_TYPES: string[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ApiRoom, IRoom } from '../types/types';
|
|
2
|
-
export declare const createRoomFromApi: (room: ApiRoom, service?: string, usersArrayLength?: number) => IRoom;
|
|
2
|
+
export declare const createRoomFromApi: (room: ApiRoom, service?: string, usersArrayLength?: number) => IRoom | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function formatNumberWithCommas(num: number | string): string;
|
|
1
|
+
export declare function formatNumberWithCommas(num: number | string, locale?: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ChatOpenPhase = 'opening' | 'settled';
|
|
2
|
+
/**
|
|
3
|
+
* Collapses "is this room's history still loading" into one phase that only
|
|
4
|
+
* ever moves forward, once, for a given room key: 'opening' -> 'settled'.
|
|
5
|
+
* It never reports 'opening' again for the same key once it has settled -
|
|
6
|
+
* ChatRoom relies on that to stop the Loader/placeholder pane from
|
|
7
|
+
* oscillating while a room opens (see the flicker this hook exists to
|
|
8
|
+
* fix). A settled-but-empty room can still legitimately start rendering
|
|
9
|
+
* messages later (a live message arrives) - that is not this hook's
|
|
10
|
+
* concern; callers derive that from their own `hasMessages`, this hook only
|
|
11
|
+
* owns whether the opening UI is still allowed to show.
|
|
12
|
+
*
|
|
13
|
+
* `roomKey` resets the latch: pass the active room's JID (or null). The
|
|
14
|
+
* reset happens synchronously during render (React's "adjust state while
|
|
15
|
+
* rendering" pattern), so switching rooms - even quickly, back and forth -
|
|
16
|
+
* never paints a frame of the previous room's settled state under the new
|
|
17
|
+
* room's key, and never leaves a stale debounce timer running against the
|
|
18
|
+
* new key (the effect below is keyed on `roomKey` too, so its cleanup
|
|
19
|
+
* clears the old timer before the new one can be scheduled).
|
|
20
|
+
*/
|
|
21
|
+
export declare const useChatOpenPhase: (roomKey: string | null, isLoadingSignal: boolean) => ChatOpenPhase;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface DelayedActionState {
|
|
2
|
+
/** Call instead of the real close/dismiss handler. */
|
|
3
|
+
requestAction: () => void;
|
|
4
|
+
/** True from the moment `requestAction` is called until `action` actually
|
|
5
|
+
* runs - apply the exit animation while this is true. */
|
|
6
|
+
isPending: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* For a component that closes ITSELF (a modal that owns `isOpen` locally,
|
|
10
|
+
* or one that only gets an `onClose` callback with no boolean to watch):
|
|
11
|
+
* wraps `action` so calling `requestAction()` plays out the exit animation
|
|
12
|
+
* first and only invokes the real `action` once it has finished, instead of
|
|
13
|
+
* unmounting on the same tick the user clicked close.
|
|
14
|
+
*
|
|
15
|
+
* This works because the component stays mounted for exactly as long as its
|
|
16
|
+
* parent's render condition stays true, and that condition usually depends
|
|
17
|
+
* on the very state `action` is about to change - delaying the call delays
|
|
18
|
+
* the unmount for free, no separate "still rendering while closing" flag
|
|
19
|
+
* needed at the parent. See `useExitTransition` for the opposite case: the
|
|
20
|
+
* parent owns `isOpen` and the child has no closing callback to intercept.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useDelayedAction(action: () => void, durationMs: number): DelayedActionState;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps the chat to at most three columns.
|
|
3
|
+
*
|
|
4
|
+
* Two different things want to be the right-hand column: the thread view
|
|
5
|
+
* (`Thread/ThreadWrapper`) and the profile/settings panel
|
|
6
|
+
* (`Modals/SidePanel`). Letting both take space at once gives four columns
|
|
7
|
+
* and squeezes the conversation into nothing, so the rule is the one most
|
|
8
|
+
* products use: THE ONE OPENED LAST WINS, and the other closes. Opening a
|
|
9
|
+
* profile while reading a thread puts the profile there and drops back to the
|
|
10
|
+
* room's messages; opening a thread from a message while a profile is open
|
|
11
|
+
* closes the profile. Either way, dismissing the survivor leaves the plain
|
|
12
|
+
* two-column chat, never a half-state.
|
|
13
|
+
*
|
|
14
|
+
* The tie-break for "both already open on the first render" (a remount with
|
|
15
|
+
* persisted state, not something a click can produce) is to close the panel:
|
|
16
|
+
* the thread is the reading context the user was in, the panel is chrome.
|
|
17
|
+
*/
|
|
18
|
+
interface UseExclusiveRightPaneOptions {
|
|
19
|
+
threadOpen: boolean;
|
|
20
|
+
panelOpen: boolean;
|
|
21
|
+
closeThread: () => void;
|
|
22
|
+
closePanel: () => void;
|
|
23
|
+
}
|
|
24
|
+
export declare const useExclusiveRightPane: ({ threadOpen, panelOpen, closeThread, closePanel, }: UseExclusiveRightPaneOptions) => void;
|
|
25
|
+
export default useExclusiveRightPane;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ExitTransitionState {
|
|
2
|
+
/** Whether the caller should still render the element at all. */
|
|
3
|
+
shouldRender: boolean;
|
|
4
|
+
/** True for the window between `isOpen` going false and the element
|
|
5
|
+
* actually leaving the DOM - apply the exit animation while this is true. */
|
|
6
|
+
isExiting: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Keeps an element mounted for `durationMs` after `isOpen` flips to false, so
|
|
10
|
+
* a CSS exit animation has time to play instead of the element vanishing on
|
|
11
|
+
* the same frame the state changes.
|
|
12
|
+
*
|
|
13
|
+
* This is the "someone else decides when I close" half of the presence
|
|
14
|
+
* story - the caller owns `isOpen` (Redux state, a prop, ...) and this hook
|
|
15
|
+
* just tells it how long to keep rendering. For a component that closes
|
|
16
|
+
* itself (a modal with its own local open flag, reacting to its own close
|
|
17
|
+
* button), prefer `useDelayedAction` instead: it lets the component play the
|
|
18
|
+
* animation and only THEN flip its own state, which is simpler when there is
|
|
19
|
+
* no external boolean to watch.
|
|
20
|
+
*
|
|
21
|
+
* Respects `prefers-reduced-motion`: when set, the element is removed on the
|
|
22
|
+
* same tick `isOpen` goes false, same as if `durationMs` were 0.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useExitTransition(isOpen: boolean, durationMs: number): ExitTransitionState;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ApiRoom } from '../types/types';
|
|
2
|
-
declare const useGetNewArchRoom: () => (client: any, config: any
|
|
2
|
+
declare const useGetNewArchRoom: () => (client: any, config: any, options?: {
|
|
3
|
+
force?: boolean;
|
|
4
|
+
}) => Promise<ApiRoom[]>;
|
|
3
5
|
export default useGetNewArchRoom;
|
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
export declare const handleQRChatId: () => void;
|
|
2
|
+
/**
|
|
3
|
+
* Turns whatever the link carried into a room JID.
|
|
4
|
+
*
|
|
5
|
+
* Accepts a bare chat id (`<appId>_<chatId>`) or an already-qualified JID,
|
|
6
|
+
* so a QR that encodes either form lands in the same room.
|
|
7
|
+
*
|
|
8
|
+
* Returns '' when no conference server is known. That is deliberate: the
|
|
9
|
+
* hook used to fall back to the build-time `VITE_APP_XMPP_CONFERENCE`, which
|
|
10
|
+
* is baked into the published bundle and is empty in this package's own
|
|
11
|
+
* build. In a multi-tenant deploy that produced a JID for the wrong tenant
|
|
12
|
+
* (or the malformed `<id>@`), so an unknown conference now means "wait",
|
|
13
|
+
* never "guess".
|
|
14
|
+
*/
|
|
15
|
+
export declare const resolveQrChatRoomJid: (qrChatId?: string | null, conferenceServer?: string) => string;
|
|
16
|
+
interface QRCodeChatOptions {
|
|
17
|
+
/** Rooms currently known to the store, keyed by JID. */
|
|
18
|
+
rooms?: Record<string, unknown> | null;
|
|
19
|
+
/** The room the store currently has selected. */
|
|
20
|
+
activeRoomJID?: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* True once the client is connected and the room list has settled, i.e.
|
|
23
|
+
* once "the room is still not here" is a real answer rather than "not
|
|
24
|
+
* loaded yet".
|
|
25
|
+
*/
|
|
26
|
+
isReady?: boolean;
|
|
27
|
+
}
|
|
2
28
|
export declare const useQRCodeChat: (setCurrentRoom: (params: {
|
|
3
29
|
roomJID: string;
|
|
4
|
-
}) => void, conferenceServer?: string) => {
|
|
30
|
+
}) => void, conferenceServer?: string, options?: QRCodeChatOptions) => {
|
|
5
31
|
wasAutoSelected: boolean;
|
|
32
|
+
notFoundRoomJID: string;
|
|
6
33
|
};
|
|
34
|
+
export {};
|