@medipha/chat 1.0.14
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 +103 -0
- package/dist/api/client.d.ts +5 -0
- package/dist/features/composer/attachment-file-helpers.d.ts +22 -0
- package/dist/features/composer/attachments/attachment-buttons.d.ts +8 -0
- package/dist/features/composer/conversation-composer.d.ts +20 -0
- package/dist/features/composer/editor/font-size-extension.d.ts +18 -0
- package/dist/features/composer/editor/mention-suggestion-list.d.ts +15 -0
- package/dist/features/composer/editor/paste-text-style.d.ts +5 -0
- package/dist/features/composer/emoji/emoji-picker-button.d.ts +9 -0
- package/dist/features/composer/emoji/emoji-shortcode-extension.d.ts +9 -0
- package/dist/features/composer/emoji/emoji-shortcodes.d.ts +2 -0
- package/dist/features/composer/format-bar/format-bar.d.ts +14 -0
- package/dist/features/composer/more-menu/more-menu.d.ts +4 -0
- package/dist/features/composer/pending-attachment.d.ts +10 -0
- package/dist/features/composer/reply/composer-reply-banner.d.ts +11 -0
- package/dist/features/composer/reply/use-reply-target.d.ts +12 -0
- package/dist/features/composer/stickers.d.ts +6 -0
- package/dist/features/composer/toolbar/composer-toolbar.d.ts +19 -0
- package/dist/features/composer/typing/use-typing-notifier.d.ts +11 -0
- package/dist/features/composer/use-attachment-upload.d.ts +4 -0
- package/dist/features/composer/use-pending-attachments.d.ts +16 -0
- package/dist/features/create-conversation/create-conversation-panel.d.ts +9 -0
- package/dist/features/create-conversation/tabs/create-group-tab.d.ts +13 -0
- package/dist/features/create-conversation/tabs/direct-chat-tab.d.ts +12 -0
- package/dist/features/create-conversation/tabs/selected-members-modal.d.ts +11 -0
- package/dist/features/files/file-attachment.d.ts +24 -0
- package/dist/features/forward/forward-dialog.d.ts +11 -0
- package/dist/features/forward/use-forward-message.d.ts +21 -0
- package/dist/features/media-preview/media-preview-modal.d.ts +23 -0
- package/dist/features/media-preview/use-image-lightbox.d.ts +16 -0
- package/dist/features/message-list/bubble/message-actions/message-actions-menu.d.ts +27 -0
- package/dist/features/message-list/bubble/message-bubble.d.ts +53 -0
- package/dist/features/message-list/bubble/message-content-body.d.ts +12 -0
- package/dist/features/message-list/bubble/message-reactions.d.ts +18 -0
- package/dist/features/message-list/bubble/rich-message-content.d.ts +8 -0
- package/dist/features/message-list/overlays/message-details/message-details-modal.d.ts +16 -0
- package/dist/features/message-list/overlays/message-details/use-message-details-modal.d.ts +14 -0
- package/dist/features/message-list/overlays/message-menu/use-message-menu.d.ts +21 -0
- package/dist/features/message-list/overlays/reaction/reaction-modal.d.ts +22 -0
- package/dist/features/message-list/overlays/reaction/use-reaction-modal.d.ts +23 -0
- package/dist/features/message-list/overlays/reaction/use-reaction-picker.d.ts +8 -0
- package/dist/features/message-list/overlays/system-members/system-members-modal.d.ts +22 -0
- package/dist/features/message-list/overlays/system-members/use-system-members-modal.d.ts +18 -0
- package/dist/features/message-list/use-message-removal.d.ts +12 -0
- package/dist/features/message-list/use-message-timeline-scroll.d.ts +25 -0
- package/dist/features/message-window/use-message-window.d.ts +46 -0
- package/dist/features/pinned-messages/pinned-messages-bar.d.ts +18 -0
- package/dist/features/pinned-messages/use-pinned-messages.d.ts +21 -0
- package/dist/features/typing/use-typing-indicator.d.ts +12 -0
- package/dist/index.cjs +278 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +66322 -0
- package/dist/module/chat-module.d.ts +3 -0
- package/dist/module/chat-module.types.d.ts +11 -0
- package/dist/module/chat-routes.d.ts +4 -0
- package/dist/module/chat-runtime-context.d.ts +5 -0
- package/dist/pages/Setting/archive/archive-attachment-preview.d.ts +13 -0
- package/dist/pages/Setting/archive/archive-file-list.d.ts +15 -0
- package/dist/pages/Setting/archive/archive-helpers.d.ts +37 -0
- package/dist/pages/Setting/archive/archive-media-grid.d.ts +14 -0
- package/dist/pages/Setting/archive/archive-view.d.ts +19 -0
- package/dist/pages/Setting/archive/hooks/use-conversation-archive.d.ts +22 -0
- package/dist/pages/Setting/conversation-settings-panel.d.ts +20 -0
- package/dist/pages/Setting/hooks/use-conversation-settings.d.ts +41 -0
- package/dist/pages/Setting/hooks/use-search-panel.d.ts +7 -0
- package/dist/pages/Setting/index.d.ts +39 -0
- package/dist/pages/Setting/members/add-member-modal.d.ts +11 -0
- package/dist/pages/Setting/members/group-members-modal.d.ts +21 -0
- package/dist/pages/Setting/members/hooks/use-rename-group-dialog.d.ts +15 -0
- package/dist/pages/Setting/members/member-selection-footer.d.ts +12 -0
- package/dist/pages/Setting/members/members-list-modal.d.ts +29 -0
- package/dist/pages/Setting/members/settings-modal.d.ts +36 -0
- package/dist/pages/Setting/members/use-member-selection.d.ts +18 -0
- package/dist/pages/Setting/search-panel.d.ts +13 -0
- package/dist/pages/conversation/conversation-detail/conversation-detail.d.ts +92 -0
- package/dist/pages/conversation/conversation-footer/conversation-footer.d.ts +42 -0
- package/dist/pages/conversation/conversation-header/conversation-header.d.ts +27 -0
- package/dist/pages/conversation/hooks/use-current-membership.d.ts +14 -0
- package/dist/pages/conversation/index.d.ts +28 -0
- package/dist/pages/conversations/empty-state/conversation-empty-state.d.ts +3 -0
- package/dist/pages/conversations/index.d.ts +4 -0
- package/dist/pages/sidebar/hooks/use-conversations.d.ts +17 -0
- package/dist/pages/sidebar/index.d.ts +4 -0
- package/dist/pages/sidebar/sidbar-conversation-list/sidbar-conversation-list.d.ts +13 -0
- package/dist/pages/sidebar/sidebar-filter/sidebar-filter.d.ts +13 -0
- package/dist/pages/sidebar/sidebar-header-infor/sidebar-header-infor.d.ts +4 -0
- package/dist/shared/components/banner-carousel.d.ts +9 -0
- package/dist/shared/components/conversation-avatar.d.ts +19 -0
- package/dist/shared/components/date-range-filter-pill.d.ts +17 -0
- package/dist/shared/components/download-action.d.ts +11 -0
- package/dist/shared/components/filter-pill.d.ts +15 -0
- package/dist/shared/components/image-not-available.d.ts +12 -0
- package/dist/shared/components/image-with-fallback.d.ts +13 -0
- package/dist/shared/components/load-more-sentinel.d.ts +15 -0
- package/dist/shared/components/quote-icon.d.ts +5 -0
- package/dist/shared/components/search-empty-state.d.ts +8 -0
- package/dist/shared/components/shared-icon.d.ts +5 -0
- package/dist/shared/components/user-avatar.d.ts +12 -0
- package/dist/shared/components/user-profile-modal.d.ts +13 -0
- package/dist/shared/components/verified-badge.d.ts +5 -0
- package/dist/shared/helper/dayjs-date-picker.d.ts +14 -0
- package/dist/shared/hooks/use-directory-filter.d.ts +13 -0
- package/dist/shared/hooks/use-user-profile-modal.d.ts +9 -0
- package/dist/socket/chatSocket.d.ts +6 -0
- package/dist/store/authStore.d.ts +34 -0
- package/dist/store/connectionStore.d.ts +8 -0
- package/dist/store/conversationsStore.d.ts +38 -0
- package/dist/store/forwardStore.d.ts +14 -0
- package/dist/store/pinnedMessagesStore.d.ts +16 -0
- package/dist/store/presenceStore.d.ts +11 -0
- package/dist/store/verifiedPermissionsStore.d.ts +20 -0
- package/dist/styles.css +2 -0
- package/dist/utils/chat-display.d.ts +44 -0
- package/dist/utils/chat-member-resolvers.d.ts +9 -0
- package/dist/utils/chat-toast.d.ts +18 -0
- package/dist/utils/chat.d.ts +282 -0
- package/dist/utils/token.d.ts +0 -0
- package/dist/utils/work-status.d.ts +15 -0
- package/package.json +96 -0
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @medipha/chat
|
|
2
|
+
|
|
3
|
+
`@medipha/chat` is an embeddable React chat module for Medic-ERP. It uses the
|
|
4
|
+
ERP application's React tree, BrowserRouter, authentication, and Ant Design 4
|
|
5
|
+
installation; it does not use an iframe or create a router.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @medipha/chat
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Mount in Medic-ERP
|
|
14
|
+
|
|
15
|
+
The ERP imports the Ant Design 4 stylesheet exactly once, at its application
|
|
16
|
+
entry point. The chat library deliberately does not import it.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import 'antd/dist/antd.css';
|
|
20
|
+
import { ChatModule } from '@medipha/chat';
|
|
21
|
+
import '@medipha/chat/styles.css';
|
|
22
|
+
|
|
23
|
+
<Route
|
|
24
|
+
path="/chat-erp/*"
|
|
25
|
+
element={
|
|
26
|
+
<ChatModule
|
|
27
|
+
accessToken={accessToken}
|
|
28
|
+
apiUrl={CHAT_API_URL}
|
|
29
|
+
socketUrl={CHAT_SOCKET_URL}
|
|
30
|
+
onUnauthorized={handleUnauthorized}
|
|
31
|
+
onNavigateOutsideChat={handleNavigateOutsideChat}
|
|
32
|
+
/>
|
|
33
|
+
}
|
|
34
|
+
/>;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The ERP must own the surrounding `BrowserRouter`. `ChatModule` adds only
|
|
38
|
+
relative routes: `/chat-erp` for the conversation list and
|
|
39
|
+
`/chat-erp/:conversationId` for a room.
|
|
40
|
+
|
|
41
|
+
## `ChatModuleProps`
|
|
42
|
+
|
|
43
|
+
| Prop | Required | Meaning |
|
|
44
|
+
| ----------------------- | -------- | --------------------------------------------------------- |
|
|
45
|
+
| `accessToken` | Yes | Current ERP access token used by chat API/socket clients. |
|
|
46
|
+
| `apiUrl` | Yes | Base URL for the Chat HTTP API. |
|
|
47
|
+
| `socketUrl` | Yes | Socket server URL. |
|
|
48
|
+
| `onUnauthorized` | No | ERP callback for an unauthorized chat response. |
|
|
49
|
+
| `onNavigateOutsideChat` | No | ERP callback for navigation that leaves chat. |
|
|
50
|
+
|
|
51
|
+
Pass a new `accessToken` prop whenever ERP refreshes its credential.
|
|
52
|
+
`ChatModule` updates its internal runtime context from the new prop and never
|
|
53
|
+
writes a token to `localStorage` or `sessionStorage`.
|
|
54
|
+
|
|
55
|
+
## Nginx SPA fallback
|
|
56
|
+
|
|
57
|
+
Configure the ERP server so deep links under `/chat-erp/*` return the ERP
|
|
58
|
+
application entry file:
|
|
59
|
+
|
|
60
|
+
```nginx
|
|
61
|
+
location / {
|
|
62
|
+
try_files $uri $uri/ /index.html;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Development and validation
|
|
67
|
+
|
|
68
|
+
Vite 8 requires Node.js `20.19+` or `22.12+`.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pnpm install
|
|
72
|
+
pnpm dev
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`pnpm dev` opens the root development playground. It loads `ChatModule`
|
|
76
|
+
directly from `src`, so library code and CSS changes use Vite HMR without a
|
|
77
|
+
library build after every edit. The playground's `BrowserRouter` is
|
|
78
|
+
development-only; it is not part of the published package.
|
|
79
|
+
|
|
80
|
+
To validate the publishable library:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pnpm typecheck
|
|
84
|
+
pnpm build
|
|
85
|
+
npm pack --dry-run
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
To verify the CRA host after building the library:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
cd examples/erp-host
|
|
92
|
+
pnpm install
|
|
93
|
+
pnpm build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Publish
|
|
97
|
+
|
|
98
|
+
Publish `@medipha/chat-core` before `@medipha/chat`. GitLab CI uses a masked,
|
|
99
|
+
protected `NPM_TOKEN` variable with npm publish permission and runs only for a
|
|
100
|
+
version tag such as `v0.1.0`. Update versions using semantic versioning: patch
|
|
101
|
+
for fixes, minor for backward-compatible features, and major for breaking API
|
|
102
|
+
changes. Create and push the version tag through your normal release process
|
|
103
|
+
after reviewing the working tree.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PendingAttachment } from './pending-attachment';
|
|
2
|
+
export declare const ACCEPT_ATTRIBUTE = ".jpg,.jpeg,.png,.webp,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt";
|
|
3
|
+
export declare const ACCEPTED_FILE_EXTENSIONS: Set<string>;
|
|
4
|
+
export declare const getFileExtension: (file: File) => string;
|
|
5
|
+
export declare const isImageFile: (file: File) => boolean;
|
|
6
|
+
/** Splits staged files into same-kind runs (images vs. documents) so each becomes one grouped message. */
|
|
7
|
+
export declare const groupAttachmentsByKind: (attachments: PendingAttachment[]) => PendingAttachment[][];
|
|
8
|
+
/** Keeps only files with a supported extension; `hasRejectedFiles` tells the caller
|
|
9
|
+
* whether to surface a format-not-supported error. */
|
|
10
|
+
export declare const splitValidAttachmentFiles: (files: File[]) => {
|
|
11
|
+
validFiles: File[];
|
|
12
|
+
hasRejectedFiles: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** Wraps a validated file as a staged attachment, generating an image preview URL when it
|
|
15
|
+
* stages as an image. `forceDocument` (set for files picked via the generic "attach file"
|
|
16
|
+
* button, as opposed to the image picker) keeps it a DOCUMENT — a file card, Zalo-style —
|
|
17
|
+
* even when the file itself happens to be a photo. */
|
|
18
|
+
export declare const buildPendingAttachment: (file: File, options?: {
|
|
19
|
+
forceDocument?: boolean;
|
|
20
|
+
}) => PendingAttachment;
|
|
21
|
+
/** Releases a staged attachment's preview URL, if it has one. */
|
|
22
|
+
export declare const revokePendingAttachmentPreview: (attachment: PendingAttachment) => void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface AttachmentButtonsProps {
|
|
2
|
+
onAttach?: () => void;
|
|
3
|
+
onAttachImages?: () => void;
|
|
4
|
+
}
|
|
5
|
+
/** Composer toolbar's file/image buttons — both just forward to the parent's staged-
|
|
6
|
+
* attachment flow (picking files/images happens outside the composer). */
|
|
7
|
+
export declare function AttachmentButtons({ onAttach, onAttachImages }: AttachmentButtonsProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ChatUser, MessageContent } from '../../utils/chat';
|
|
2
|
+
interface ConversationComposerProps {
|
|
3
|
+
conversationName: string;
|
|
4
|
+
members: ChatUser[];
|
|
5
|
+
canMentionAll: boolean;
|
|
6
|
+
/** Enables @mentions; turned off for 1-1 chats where there's nobody to tag. */
|
|
7
|
+
enableMentions?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Allows sending with an empty editor (attachments staged in the parent are the payload). */
|
|
10
|
+
hasPendingAttachments?: boolean;
|
|
11
|
+
onSubmit: (content: MessageContent) => void;
|
|
12
|
+
onError?: (message: string) => void;
|
|
13
|
+
onAttach?: () => void;
|
|
14
|
+
onAttachImages?: () => void;
|
|
15
|
+
onTypingStart?: () => void;
|
|
16
|
+
onTypingStop?: () => void;
|
|
17
|
+
}
|
|
18
|
+
/** Rich-text composer that emits backend message content, with real @mentions. */
|
|
19
|
+
export declare function ConversationComposer({ conversationName, members, canMentionAll, enableMentions, disabled, hasPendingAttachments, onSubmit, onError, onAttach, onAttachImages, onTypingStart, onTypingStop, }: ConversationComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
declare module '@tiptap/core' {
|
|
3
|
+
interface Commands<ReturnType> {
|
|
4
|
+
fontSize: {
|
|
5
|
+
/** Sets the fontSize attribute on the textStyle mark over the current selection. */
|
|
6
|
+
setFontSize: (fontSize: string) => ReturnType;
|
|
7
|
+
/** Clears the fontSize attribute, falling back to the editor's base size. */
|
|
8
|
+
unsetFontSize: () => ReturnType;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* No stable official `@tiptap/extension-font-size` exists yet for this TipTap version
|
|
14
|
+
* (only a `3.0.0-next.*` prerelease) — this mirrors `@tiptap/extension-color`'s own
|
|
15
|
+
* approach (extend the shared `textStyle` mark with one more attribute) so `color` and
|
|
16
|
+
* `fontSize` compose on the same mark instead of fighting over it.
|
|
17
|
+
*/
|
|
18
|
+
export declare const FontSize: Extension<any, any>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface MentionItem {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
fallbackName?: string;
|
|
5
|
+
avatarUrl?: string | null;
|
|
6
|
+
isAll?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface MentionSuggestionListProps {
|
|
9
|
+
items: MentionItem[];
|
|
10
|
+
selectedIndex: number;
|
|
11
|
+
onSelect: (index: number) => void;
|
|
12
|
+
}
|
|
13
|
+
/** Zalo-style @mention dropdown: hint row, an "@All" option, then members with avatars. */
|
|
14
|
+
export declare function MentionSuggestionList({ items, selectedIndex, onSelect }: MentionSuggestionListProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Sanitizes pasted HTML's inline `color`/`font-size` down to whichever of our fixed
|
|
2
|
+
* swatches/sizes they exactly match, or strips them entirely otherwise — done at paste
|
|
3
|
+
* time so what lands in the composer already matches what will actually be sent, instead
|
|
4
|
+
* of only being caught by the same check later at send time. */
|
|
5
|
+
export declare function sanitizePastedTextStyle(html: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
interface EmojiPickerButtonProps {
|
|
3
|
+
editor: Editor | null | undefined;
|
|
4
|
+
}
|
|
5
|
+
/** Composer toolbar's smiley button: toggles a native-emoji picker popover and inserts
|
|
6
|
+
* the picked emoji at the cursor. Stays open after a pick so several emoji can be
|
|
7
|
+
* chosen in a row. */
|
|
8
|
+
export declare function EmojiPickerButton({ editor }: EmojiPickerButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* Replaces chat emoticon shortcodes (":v", ":)", "<3", ...) with the matching emoji.
|
|
4
|
+
*
|
|
5
|
+
* Runs on a short pause after typing, not on every keystroke: firing instantly would
|
|
6
|
+
* convert ":)" the moment its two characters appear, before the user can extend it into
|
|
7
|
+
* ":)))" — the extra parens would then just land as literal text after the emoji.
|
|
8
|
+
*/
|
|
9
|
+
export declare const EmojiShortcodeExtension: Extension<any, any>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
interface FormatBarProps {
|
|
4
|
+
editor: Editor | null | undefined;
|
|
5
|
+
isEnlarged: boolean;
|
|
6
|
+
onToggleEnlarged: () => void;
|
|
7
|
+
/** Rendered at the right edge of the bar — the same send button shown in the input
|
|
8
|
+
* row when this bar is closed. */
|
|
9
|
+
sendButton: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/** Rich-text format bar shown while the composer's "Định dạng" toggle is on: bold/italic/
|
|
12
|
+
* underline/strike, font size, text color, clear, lists, undo/redo, and the enlarge toggle. */
|
|
13
|
+
export declare function FormatBar({ editor, isEnlarged, onToggleEnlarged, sendButton }: FormatBarProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The composer's "..." button: opens a small menu (currently just "Tạo công việc").
|
|
2
|
+
* "Tạo công việc" is still scaffolded and just shows a "coming soon" toast, since
|
|
3
|
+
* there's no backend for it yet. */
|
|
4
|
+
export declare function MoreMenu(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A file staged in the composer, not yet sent. */
|
|
2
|
+
export interface PendingAttachment {
|
|
3
|
+
file: File;
|
|
4
|
+
previewUrl?: string;
|
|
5
|
+
/** Whether this stages as an IMAGE message (inline preview) or a DOCUMENT (file card) —
|
|
6
|
+
* resolved once at staging time (see buildPendingAttachment) so every later step
|
|
7
|
+
* (grouping, the outgoing message's own `type`, the upload request) agrees on it,
|
|
8
|
+
* instead of each re-deriving it from the file's extension. */
|
|
9
|
+
isImage: boolean;
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChatMessage } from '../../../utils/chat';
|
|
2
|
+
interface ComposerReplyBannerProps {
|
|
3
|
+
target: ChatMessage;
|
|
4
|
+
avatarUrl?: string | null;
|
|
5
|
+
senderName: string;
|
|
6
|
+
onCancel: () => void;
|
|
7
|
+
}
|
|
8
|
+
/** Shown above the composer while replying to a message: sender avatar/name + a short
|
|
9
|
+
* preview of what's being replied to, with a button to cancel the reply. */
|
|
10
|
+
export declare function ComposerReplyBanner({ target, avatarUrl, senderName, onCancel }: ComposerReplyBannerProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ChatMessage } from '../../../utils/chat';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks the message the composer is currently replying to — set from a bubble's
|
|
4
|
+
* "Reply" action, read by the composer's reply banner and included in the next send,
|
|
5
|
+
* cleared on submit or when its target message is removed/recalled.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useReplyTarget(): {
|
|
8
|
+
replyTarget: ChatMessage | null;
|
|
9
|
+
startReply: (message: ChatMessage) => void;
|
|
10
|
+
clearReply: () => void;
|
|
11
|
+
clearIfTarget: (messageId: string) => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sticker tray content. Rendered large and sent immediately on tap (unlike the emoji
|
|
3
|
+
* picker, which inserts into the compose box). Backed by emoji glyphs for now — swap
|
|
4
|
+
* for real sticker image assets later without changing the composer/bubble contract.
|
|
5
|
+
*/
|
|
6
|
+
export declare const STICKERS: string[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
interface ComposerToolbarProps {
|
|
4
|
+
editor: Editor | null | undefined;
|
|
5
|
+
onAttach?: () => void;
|
|
6
|
+
onAttachImages?: () => void;
|
|
7
|
+
isFormatOpen: boolean;
|
|
8
|
+
onToggleFormat: () => void;
|
|
9
|
+
isEnlarged: boolean;
|
|
10
|
+
onToggleEnlarged: () => void;
|
|
11
|
+
/** Shared send button — rendered here (on the format bar) when it's open, or by the
|
|
12
|
+
* parent composer's input row otherwise; never both at once. */
|
|
13
|
+
sendButton: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/** Composer toolbar row: attach file/image, the "Định dạng" toggle, the emoji picker, and
|
|
16
|
+
* the "..." more menu — plus the format bar it reveals underneath when toggled open. Each
|
|
17
|
+
* button's own popover/panel lives in its own feature folder; this just arranges them. */
|
|
18
|
+
export declare function ComposerToolbar({ editor, onAttach, onAttachImages, isFormatOpen, onToggleFormat, isEnlarged, onToggleEnlarged, sendButton, }: ComposerToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface UseTypingNotifierOptions {
|
|
2
|
+
onTypingStart?: () => void;
|
|
3
|
+
onTypingStop?: () => void;
|
|
4
|
+
}
|
|
5
|
+
/** Emits typing:start at most once per burst of edits, then typing:stop after ~5s of
|
|
6
|
+
* inactivity, a send, or unmount — whichever comes first. */
|
|
7
|
+
export declare function useTypingNotifier({ onTypingStart, onTypingStop }: UseTypingNotifierOptions): {
|
|
8
|
+
notifyTyping: () => void;
|
|
9
|
+
stopTyping: () => void;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ChatMessage } from '../../utils/chat';
|
|
2
|
+
/** Uploads a message's staged files, then emits it as a normal outgoing message. Used both
|
|
3
|
+
* for sending a fresh attachment message and for retrying one that previously failed. */
|
|
4
|
+
export declare function useAttachmentUpload(emitOutgoingMessage: (message: ChatMessage) => void, markMessageFailed: (message: ChatMessage, failureStage: 'upload' | 'send') => void, mergeOutgoingMessage: (message: ChatMessage) => void): (message: ChatMessage) => Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PendingAttachment } from './pending-attachment';
|
|
2
|
+
/**
|
|
3
|
+
* Owns the files staged in the composer before send: validating/adding picked files,
|
|
4
|
+
* removing one, and clearing the whole batch — either after a successful send (files are
|
|
5
|
+
* already handed off, no preview URLs to release) or when discarding them outright (e.g.
|
|
6
|
+
* switching conversations), which does release every preview URL.
|
|
7
|
+
*/
|
|
8
|
+
export declare function usePendingAttachments(): {
|
|
9
|
+
pendingAttachments: PendingAttachment[];
|
|
10
|
+
addFiles: (files: File[], options?: {
|
|
11
|
+
forceDocument?: boolean;
|
|
12
|
+
}) => boolean;
|
|
13
|
+
removeAt: (index: number) => void;
|
|
14
|
+
clear: () => void;
|
|
15
|
+
discardAll: () => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Conversation } from '../../utils/chat';
|
|
2
|
+
interface CreateConversationPanelProps {
|
|
3
|
+
currentUserId: string | null;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onCreated: (conversation: Conversation) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Modal panel to start a direct chat or create a named group conversation. */
|
|
8
|
+
export declare function CreateConversationPanel({ currentUserId, onClose, onCreated, }: CreateConversationPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ChatUser } from '../../../utils/chat';
|
|
2
|
+
interface CreateGroupTabProps {
|
|
3
|
+
users: ChatUser[];
|
|
4
|
+
groupTitle: string;
|
|
5
|
+
isCreating: boolean;
|
|
6
|
+
isLoadingUsers: boolean;
|
|
7
|
+
error: string;
|
|
8
|
+
onSubmit: (title: string, memberIds: string[], isVerified: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
/** "Nhóm" tab — check off members, submit to create the group (title input lives in the
|
|
11
|
+
* parent panel, above the department/branch filters). */
|
|
12
|
+
export declare function CreateGroupTab({ users, groupTitle, isCreating, isLoadingUsers, error, onSubmit, }: CreateGroupTabProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ChatUser } from '../../../utils/chat';
|
|
2
|
+
interface DirectChatTabProps {
|
|
3
|
+
users: ChatUser[];
|
|
4
|
+
isCreating: boolean;
|
|
5
|
+
/** True while the list for the current filters is being fetched. */
|
|
6
|
+
isLoadingUsers: boolean;
|
|
7
|
+
error: string;
|
|
8
|
+
onSelectUser: (user: ChatUser) => void;
|
|
9
|
+
}
|
|
10
|
+
/** "Trò chuyện" tab — pick a user to start (or reuse) a direct conversation with. */
|
|
11
|
+
export declare function DirectChatTab({ users, isCreating, isLoadingUsers, error, onSelectUser, }: DirectChatTabProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChatUser } from '../../../utils/chat';
|
|
2
|
+
interface SelectedMembersModalProps {
|
|
3
|
+
users: ChatUser[];
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onRemove: (user: ChatUser) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Read-only-ish review of who's picked so far for the new group, opened from the
|
|
8
|
+
* "Đã chọn N thành viên" count — each row can also be unchecked without hunting it
|
|
9
|
+
* back down in the (possibly filtered/paginated) main list. */
|
|
10
|
+
export declare function SelectedMembersModal({ users, onClose, onRemove }: SelectedMembersModalProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ChatMessageAttachment } from '../../utils/chat';
|
|
2
|
+
interface FileAttachmentProps {
|
|
3
|
+
attachment: ChatMessageAttachment;
|
|
4
|
+
/** Optional secondary line (e.g. sender · time) shown under the file name. */
|
|
5
|
+
meta?: string;
|
|
6
|
+
/** When provided, a "share" (forward) button is shown as the first action. */
|
|
7
|
+
onShare?: () => void;
|
|
8
|
+
/** When provided, a 4th action jumps back to the message this attachment was sent in. */
|
|
9
|
+
onJumpToMessage?: () => void;
|
|
10
|
+
/**
|
|
11
|
+
* Settings/archive layout: the whole card is clickable to preview and gets a subtle hover
|
|
12
|
+
* zoom. Chat bubbles leave this off. The action row is always on the same line as the
|
|
13
|
+
* size · time text regardless of this flag — only the clickable-card/hover behavior
|
|
14
|
+
* differs by variant now.
|
|
15
|
+
*/
|
|
16
|
+
inline?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reusable file card: type icon + wrapping name + size, with Preview (opens the file in a
|
|
20
|
+
* new tab) and Download actions, plus optional Share. Used in chat bubbles, the settings
|
|
21
|
+
* document list, and the archive.
|
|
22
|
+
*/
|
|
23
|
+
export declare function FileAttachment({ attachment, meta, onShare, onJumpToMessage, inline }: FileAttachmentProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChatMessage } from '../../utils/chat';
|
|
2
|
+
interface ForwardDialogProps {
|
|
3
|
+
source: ChatMessage;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onForward: (targetConversationIds: string[], note: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Zalo-style forward picker: choose one or more conversations to forward a message into.
|
|
8
|
+
* Built on the shared settings-modal shell/list/checkbox components (same ones the
|
|
9
|
+
* add-member and create-group pickers use) instead of one-off markup. */
|
|
10
|
+
export declare function ForwardDialog({ source, onClose, onForward }: ForwardDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface UseForwardMessageOptions {
|
|
2
|
+
/** Called once a forward has actually been emitted — re-pins the scroll, since a
|
|
3
|
+
* forwarded image resizes its bubble once it loads and can otherwise settle mid-list
|
|
4
|
+
* instead of following down, same as a normal send. */
|
|
5
|
+
onForwarded: () => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Owns the "Chuyển tiếp" (forward) submit flow: the socket calls that send the staged
|
|
9
|
+
* message on to the picked conversations, with an optional note sent ahead of it.
|
|
10
|
+
* Which message is staged (and whether ForwardDialog is open) comes from the shared
|
|
11
|
+
* `forwardStore` — `openForward`/`closeForward`/`clearIfTarget` are that store's actions
|
|
12
|
+
* directly, re-exported here only so existing call sites don't need to change.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useForwardMessage({ onForwarded }: UseForwardMessageOptions): {
|
|
15
|
+
forwardSource: import('../../utils/chat').ChatMessage | null;
|
|
16
|
+
openForward: (message: import('../../utils/chat').ChatMessage) => void;
|
|
17
|
+
closeForward: () => void;
|
|
18
|
+
clearIfTarget: (messageId: string) => void;
|
|
19
|
+
submitForward: (targetConversationIds: string[], note: string) => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface MediaPreviewItem {
|
|
2
|
+
id: string;
|
|
3
|
+
url: string;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
name?: string | null;
|
|
6
|
+
}
|
|
7
|
+
export interface MediaPreviewState {
|
|
8
|
+
items: MediaPreviewItem[];
|
|
9
|
+
index: number;
|
|
10
|
+
}
|
|
11
|
+
interface MediaPreviewModalProps {
|
|
12
|
+
state: MediaPreviewState;
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
onIndexChange: (index: number) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Zalo-style fullscreen photo viewer: current image large + a thumbnail rail (grouped by
|
|
18
|
+
* day). The rail's own arrows move to the prev/next image too (same as the main ones) —
|
|
19
|
+
* the active thumbnail auto-scrolls into view, so one pair of controls covers both.
|
|
20
|
+
* Reused by chat bubbles, the settings media teaser, and the archive ("Kho lưu trữ").
|
|
21
|
+
*/
|
|
22
|
+
export declare function MediaPreviewModal({ state, onClose, onIndexChange }: MediaPreviewModalProps): import("react/jsx-runtime").JSX.Element | null;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { flattenFileEntries } from '../../pages/Setting/archive/archive-helpers';
|
|
2
|
+
import { ChatMessage } from '../../utils/chat';
|
|
3
|
+
import { MediaPreviewState } from './media-preview-modal';
|
|
4
|
+
/**
|
|
5
|
+
* Owns the fullscreen media-preview overlay. `openFromBubble` resolves a bubble image
|
|
6
|
+
* click to its position in the conversation's full media archive ("Kho lưu trữ") so the
|
|
7
|
+
* rail shows every image, not just this message's own — falling back to just that
|
|
8
|
+
* message's own images if the archive hasn't loaded (or doesn't have this image) yet.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useImageLightbox(): {
|
|
11
|
+
imageLightbox: MediaPreviewState | null;
|
|
12
|
+
openItems: (items: MediaPreviewState["items"], index: number) => void;
|
|
13
|
+
openFromBubble: (message: ChatMessage, mediaArchiveItems: Parameters<typeof flattenFileEntries>[0], urls: string[], clickedIndex: number) => void;
|
|
14
|
+
setIndex: (index: number) => void;
|
|
15
|
+
close: () => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
interface MessageActionsMenuProps {
|
|
2
|
+
canRemove: boolean;
|
|
3
|
+
removeLabel: string;
|
|
4
|
+
isRemoving: boolean;
|
|
5
|
+
canManagePins: boolean;
|
|
6
|
+
/** Whether the message has copyable text — false for image/file-only messages. */
|
|
7
|
+
canCopy: boolean;
|
|
8
|
+
canForward: boolean;
|
|
9
|
+
isPinned: boolean;
|
|
10
|
+
isMenuOpen: boolean;
|
|
11
|
+
menuPosition: {
|
|
12
|
+
top?: number;
|
|
13
|
+
bottom?: number;
|
|
14
|
+
left: number;
|
|
15
|
+
} | null;
|
|
16
|
+
onReply: () => void;
|
|
17
|
+
onForward: () => void;
|
|
18
|
+
onOpenMenu: (triggerRect: DOMRect) => void;
|
|
19
|
+
onCloseMenu: () => void;
|
|
20
|
+
onCopyMessage: () => void;
|
|
21
|
+
onTogglePin: () => void;
|
|
22
|
+
onViewDetails: () => void;
|
|
23
|
+
onRemove: () => void;
|
|
24
|
+
}
|
|
25
|
+
/** Reply/forward buttons plus the "..." options menu (copy / pin / details / recall). */
|
|
26
|
+
export declare function MessageActionsMenu({ canRemove, removeLabel, isRemoving, canManagePins, canCopy, canForward, isPinned, isMenuOpen, menuPosition, onReply, onForward, onOpenMenu, onCloseMenu, onCopyMessage, onTogglePin, onViewDetails, onRemove, }: MessageActionsMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ChatMessage } from '../../../utils/chat';
|
|
2
|
+
import { ReactionType } from '@medipha/chat-core';
|
|
3
|
+
export interface MessageBubbleProps {
|
|
4
|
+
message: ChatMessage;
|
|
5
|
+
isMine: boolean;
|
|
6
|
+
/** Shows the sender's name above incoming bubbles — group chats only (Zalo/Messenger-style). */
|
|
7
|
+
isGroup: boolean;
|
|
8
|
+
isFocused: boolean;
|
|
9
|
+
isLatestMessage: boolean;
|
|
10
|
+
showDayDivider: boolean;
|
|
11
|
+
isReactionPickerOpen: boolean;
|
|
12
|
+
myReactionType: ReactionType | null;
|
|
13
|
+
onOpenReactionPicker: () => void;
|
|
14
|
+
onCloseReactionPickerIfSelf: () => void;
|
|
15
|
+
onApplyReaction: (type: ReactionType) => void;
|
|
16
|
+
onRemoveReaction: () => void;
|
|
17
|
+
onOpenReactionModal: () => void;
|
|
18
|
+
canManagePins: boolean;
|
|
19
|
+
isPinned: boolean;
|
|
20
|
+
onTogglePin: () => void;
|
|
21
|
+
isMenuOpen: boolean;
|
|
22
|
+
menuPosition: {
|
|
23
|
+
top?: number;
|
|
24
|
+
bottom?: number;
|
|
25
|
+
left: number;
|
|
26
|
+
} | null;
|
|
27
|
+
onOpenMenu: (triggerRect: DOMRect) => void;
|
|
28
|
+
onCloseMenu: () => void;
|
|
29
|
+
onCopyMessage: () => void;
|
|
30
|
+
onViewDetails: () => void;
|
|
31
|
+
canRemove: boolean;
|
|
32
|
+
removeLabel: string;
|
|
33
|
+
isRemoving: boolean;
|
|
34
|
+
onRemove: () => void;
|
|
35
|
+
onReply: () => void;
|
|
36
|
+
onForward: () => void;
|
|
37
|
+
onJumpToReply: (replyMessageId: string) => void;
|
|
38
|
+
onOpenMentionCard: (userId: string, fallbackName?: string) => void;
|
|
39
|
+
onOpenSystemMembers: (messageId: string, totalCount: number, actionLabel: string) => void;
|
|
40
|
+
onOpenImageLightbox: (urls: string[], index: number) => void;
|
|
41
|
+
onImageSettled: () => void;
|
|
42
|
+
onRetry: () => void;
|
|
43
|
+
/** Failed send never reached the server (no `id`) — this is a local-only delete, not a recall. */
|
|
44
|
+
onDeleteFailed: () => void;
|
|
45
|
+
/** Resolves a userId to their avatar photo URL, or null to fall back to initials. */
|
|
46
|
+
resolveUserAvatar?: (userId?: string) => string | null;
|
|
47
|
+
/** Opens the account-info modal for the sender when their avatar is clicked. */
|
|
48
|
+
onOpenUserProfile?: (userId: string) => void;
|
|
49
|
+
}
|
|
50
|
+
/** Renders one message: day divider, SYSTEM notice, reply/forward context, bubble body
|
|
51
|
+
* (delegated to MessageContentBody), reaction badge/picker (MessageReactions), action buttons
|
|
52
|
+
* and options menu (MessageActionsMenu), and the trailing timestamp/status/retry. */
|
|
53
|
+
export declare function MessageBubble({ message, isMine, isGroup, isFocused, isLatestMessage, showDayDivider, isReactionPickerOpen, myReactionType, onOpenReactionPicker, onCloseReactionPickerIfSelf, onApplyReaction, onRemoveReaction, onOpenReactionModal, canManagePins, isPinned, onTogglePin, isMenuOpen, menuPosition, onOpenMenu, onCloseMenu, onCopyMessage, onViewDetails, canRemove, removeLabel, isRemoving, onRemove, onReply, onForward, onJumpToReply, onOpenMentionCard, onOpenSystemMembers, onOpenImageLightbox, onImageSettled, onRetry, onDeleteFailed, resolveUserAvatar, onOpenUserProfile, }: MessageBubbleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ChatMessage } from '../../../utils/chat';
|
|
2
|
+
interface MessageContentBodyProps {
|
|
3
|
+
message: ChatMessage;
|
|
4
|
+
isLatestMessage: boolean;
|
|
5
|
+
onOpenImageLightbox: (urls: string[], index: number) => void;
|
|
6
|
+
onImageSettled: () => void;
|
|
7
|
+
onOpenMentionCard: (userId: string, fallbackName?: string) => void;
|
|
8
|
+
}
|
|
9
|
+
/** The bubble's inner content: image grid, document attachment(s), or marked-up text
|
|
10
|
+
* with clickable links/mentions — whichever the message type calls for. */
|
|
11
|
+
export declare function MessageContentBody({ message, isLatestMessage, onOpenImageLightbox, onImageSettled, onOpenMentionCard, }: MessageContentBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactionType } from '@medipha/chat-core';
|
|
2
|
+
import { ChatMessage } from '../../../utils/chat';
|
|
3
|
+
interface MessageReactionsProps {
|
|
4
|
+
message: ChatMessage;
|
|
5
|
+
isPickerOpen: boolean;
|
|
6
|
+
myReactionType: ReactionType | null;
|
|
7
|
+
onOpenPicker: () => void;
|
|
8
|
+
onClosePickerIfSelf: () => void;
|
|
9
|
+
onApplyReaction: (type: ReactionType) => void;
|
|
10
|
+
onRemoveReaction: () => void;
|
|
11
|
+
onOpenModal: () => void;
|
|
12
|
+
}
|
|
13
|
+
/** Compact aggregate reaction badge plus a separate hover-triggered picker for applying a type.
|
|
14
|
+
* Messenger-style trigger: shows a generic smiley until you've reacted, then shows your
|
|
15
|
+
* own reaction's emoji instead — clicking it directly re-applies that same reaction, and
|
|
16
|
+
* hovering still opens the picker to switch to a different one. */
|
|
17
|
+
export declare function MessageReactions({ message, isPickerOpen, myReactionType, onOpenPicker, onClosePickerIfSelf, onApplyReaction, onRemoveReaction, onOpenModal, }: MessageReactionsProps): import("react/jsx-runtime").JSX.Element | null;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RichMessageDocument } from '../../../utils/chat';
|
|
2
|
+
interface RichMessageContentProps {
|
|
3
|
+
content: RichMessageDocument;
|
|
4
|
+
onOpenMentionCard: (userId: string, fallbackName?: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Renders backend rich content with the same Tiptap structure as the composer, read-only. */
|
|
7
|
+
export declare function RichMessageContent({ content, onOpenMentionCard }: RichMessageContentProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|