@webinex/chatify 1.0.0-alpha03 → 1.0.0-alpha05
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/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/ui/ChatListItem.d.ts +11 -0
- package/dist/cjs/types/ui/ChatName.d.ts +5 -0
- package/dist/cjs/types/ui/Chatify.d.ts +22 -0
- package/dist/cjs/types/ui/Message.d.ts +14 -1
- package/dist/cjs/types/ui/SendingMessage.d.ts +5 -1
- package/dist/cjs/types/ui/index.d.ts +1 -0
- package/dist/css/chatify.css +67 -11
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/ui/ChatListItem.d.ts +11 -0
- package/dist/esm/types/ui/ChatName.d.ts +5 -0
- package/dist/esm/types/ui/Chatify.d.ts +22 -0
- package/dist/esm/types/ui/Message.d.ts +14 -1
- package/dist/esm/types/ui/SendingMessage.d.ts +5 -1
- package/dist/esm/types/ui/index.d.ts +1 -0
- package/dist/index.d.ts +66 -7
- package/package.json +1 -1
- package/src/core/reducer.tsx +8 -2
- package/src/ui/Aside.tsx +3 -30
- package/src/ui/ChatHeader.tsx +3 -1
- package/src/ui/ChatListItem.tsx +101 -0
- package/src/ui/ChatName.tsx +15 -0
- package/src/ui/Chatify.tsx +42 -0
- package/src/ui/Message.tsx +102 -35
- package/src/ui/SendingMessage.tsx +41 -5
- package/src/ui/index.ts +1 -0
- package/src/ui/styles/index.scss +11 -6
- package/dist/cjs/types/ui/MessageMd.d.ts +0 -13
- package/dist/esm/types/ui/MessageMd.d.ts +0 -13
- package/src/ui/MessageMd.tsx +0 -47
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
import { FC, Ref, RefObject } from 'react';
|
|
1
2
|
import { Message as MessageModel } from '../core';
|
|
2
3
|
export interface MessageProps {
|
|
3
4
|
message: MessageModel;
|
|
4
5
|
}
|
|
5
|
-
export
|
|
6
|
+
export interface MessageBoxProps extends MessageProps {
|
|
7
|
+
containerRef?: Ref<HTMLDivElement>;
|
|
8
|
+
}
|
|
9
|
+
export declare const MessageAuthor: import("../util").Customizable<FC<MessageProps>, string>;
|
|
10
|
+
export declare const MessageText: import("../util").Customizable<FC<MessageProps>, string>;
|
|
11
|
+
export declare const MessageInfoBox: import("../util").Customizable<FC<MessageProps>, string>;
|
|
12
|
+
export declare const MessageBody: import("../util").Customizable<FC<MessageProps>, string>;
|
|
13
|
+
export declare const MessageBox: import("../util").Customizable<FC<MessageBoxProps>, string>;
|
|
14
|
+
export declare const Message: import("../util").Customizable<FC<MessageProps>, string>;
|
|
15
|
+
export interface MessageReadObserverProps extends MessageProps {
|
|
16
|
+
messageRef: RefObject<HTMLDivElement | null>;
|
|
17
|
+
}
|
|
18
|
+
export declare const MessageReadObserver: import("../util").Customizable<FC<MessageReadObserverProps>, string>;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
1
2
|
import { File } from '../core';
|
|
2
3
|
export interface SendingMessageProps {
|
|
3
4
|
text: string;
|
|
4
5
|
files: File[];
|
|
5
6
|
}
|
|
6
|
-
export declare
|
|
7
|
+
export declare const SendingMessageText: import("../util").Customizable<FC<SendingMessageProps>, string>;
|
|
8
|
+
export declare const SendingMessageInfoBox: import("../util").Customizable<FC<SendingMessageProps>, string>;
|
|
9
|
+
export declare const SendingMessageBody: import("../util").Customizable<FC<SendingMessageProps>, string>;
|
|
10
|
+
export declare const SendingMessage: import("../util").Customizable<FC<SendingMessageProps>, string>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { PropsWithChildren, FC, CSSProperties } from 'react';
|
|
1
|
+
import React, { PropsWithChildren, FC, Ref, RefObject, CSSProperties } from 'react';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import { AxiosInstance } from 'axios';
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ interface Account {
|
|
|
45
45
|
name: string;
|
|
46
46
|
avatar: string;
|
|
47
47
|
}
|
|
48
|
-
interface Message {
|
|
48
|
+
interface Message$1 {
|
|
49
49
|
id: string;
|
|
50
50
|
chatId: string;
|
|
51
51
|
text: string;
|
|
@@ -63,7 +63,7 @@ interface Chat {
|
|
|
63
63
|
interface ChatListItem {
|
|
64
64
|
id: string;
|
|
65
65
|
name: string;
|
|
66
|
-
message: Message;
|
|
66
|
+
message: Message$1;
|
|
67
67
|
unreadCount: number;
|
|
68
68
|
}
|
|
69
69
|
interface SendMessageRequest {
|
|
@@ -127,7 +127,7 @@ declare class ChatifyClient {
|
|
|
127
127
|
chatId: string;
|
|
128
128
|
skip?: number;
|
|
129
129
|
take?: number;
|
|
130
|
-
}) => Promise<Message[]>;
|
|
130
|
+
}) => Promise<Message$1[]>;
|
|
131
131
|
send: (request: SendMessageRequest) => Promise<void>;
|
|
132
132
|
read: (request: ReadRequest) => Promise<void>;
|
|
133
133
|
removeMember: (request: RemoveMemberRequest) => Promise<void>;
|
|
@@ -192,7 +192,7 @@ declare const ACTIONS: {
|
|
|
192
192
|
chatId: string;
|
|
193
193
|
}) => State;
|
|
194
194
|
message_received: (state: State, { message, requestId }: {
|
|
195
|
-
message: Message;
|
|
195
|
+
message: Message$1;
|
|
196
196
|
requestId: string;
|
|
197
197
|
}) => State;
|
|
198
198
|
chat_created: (state: State, { chat }: {
|
|
@@ -251,7 +251,7 @@ declare function useLoadMore({ chatId }: {
|
|
|
251
251
|
|
|
252
252
|
type MessageState = ({
|
|
253
253
|
type: 'message';
|
|
254
|
-
} & Message) | {
|
|
254
|
+
} & Message$1) | {
|
|
255
255
|
type: 'more';
|
|
256
256
|
} | {
|
|
257
257
|
type: 'sending';
|
|
@@ -296,6 +296,47 @@ declare const AddChatButton: Customizable<FC, "AddChatButton">;
|
|
|
296
296
|
|
|
297
297
|
declare const Footer: Customizable<FC, "Footer">;
|
|
298
298
|
|
|
299
|
+
interface ChatNameProps {
|
|
300
|
+
name: string;
|
|
301
|
+
}
|
|
302
|
+
declare const ChatName: Customizable<FC<ChatNameProps>, "ChatName">;
|
|
303
|
+
|
|
304
|
+
interface ChatListItemProps {
|
|
305
|
+
chat: ChatListItem;
|
|
306
|
+
}
|
|
307
|
+
declare const ChatListItemName: Customizable<FC<ChatListItemProps>, "ChatListItemName">;
|
|
308
|
+
declare const ChatListItemUnreadCount: Customizable<FC<ChatListItemProps>, "ChatListItemUnreadCount">;
|
|
309
|
+
declare const ChatListItemLastMessage: Customizable<FC<ChatListItemProps>, "ChatListItemLastMessage">;
|
|
310
|
+
declare const ChatListItemLastMessageAuthor: Customizable<FC<ChatListItemProps>, string>;
|
|
311
|
+
declare const ChatListItemLastMessageContent: Customizable<FC<ChatListItemProps>, string>;
|
|
312
|
+
declare const ChatListItemView: Customizable<FC<ChatListItemProps>, "ChatListItemView">;
|
|
313
|
+
|
|
314
|
+
interface SendingMessageProps {
|
|
315
|
+
text: string;
|
|
316
|
+
files: File[];
|
|
317
|
+
}
|
|
318
|
+
declare const SendingMessageText: Customizable<FC<SendingMessageProps>, string>;
|
|
319
|
+
declare const SendingMessageInfoBox: Customizable<FC<SendingMessageProps>, string>;
|
|
320
|
+
declare const SendingMessageBody: Customizable<FC<SendingMessageProps>, string>;
|
|
321
|
+
declare const SendingMessage: Customizable<FC<SendingMessageProps>, string>;
|
|
322
|
+
|
|
323
|
+
interface MessageProps {
|
|
324
|
+
message: Message$1;
|
|
325
|
+
}
|
|
326
|
+
interface MessageBoxProps extends MessageProps {
|
|
327
|
+
containerRef?: Ref<HTMLDivElement>;
|
|
328
|
+
}
|
|
329
|
+
declare const MessageAuthor: Customizable<FC<MessageProps>, string>;
|
|
330
|
+
declare const MessageText: Customizable<FC<MessageProps>, string>;
|
|
331
|
+
declare const MessageInfoBox: Customizable<FC<MessageProps>, string>;
|
|
332
|
+
declare const MessageBody: Customizable<FC<MessageProps>, string>;
|
|
333
|
+
declare const MessageBox: Customizable<FC<MessageBoxProps>, string>;
|
|
334
|
+
declare const Message: Customizable<FC<MessageProps>, string>;
|
|
335
|
+
interface MessageReadObserverProps extends MessageProps {
|
|
336
|
+
messageRef: RefObject<HTMLDivElement | null>;
|
|
337
|
+
}
|
|
338
|
+
declare const MessageReadObserver: Customizable<FC<MessageReadObserverProps>, string>;
|
|
339
|
+
|
|
299
340
|
interface ChatifyCustomizeValue {
|
|
300
341
|
Avatar?: typeof Avatar.Component | null;
|
|
301
342
|
Header?: typeof Header.Component | null;
|
|
@@ -303,6 +344,24 @@ interface ChatifyCustomizeValue {
|
|
|
303
344
|
AddChatButton?: typeof AddChatButton.Component | null;
|
|
304
345
|
ChatHeaderMembers?: typeof ChatHeaderMembers.Component | null;
|
|
305
346
|
ChatSettingsButton?: typeof ChatSettingsButton.Component | null;
|
|
347
|
+
ChatName?: typeof ChatName.Component | null;
|
|
348
|
+
ChatListItem?: typeof ChatListItemView.Component | null;
|
|
349
|
+
ChatListItemName?: typeof ChatListItemName.Component | null;
|
|
350
|
+
ChatListItemUnreadCount?: typeof ChatListItemUnreadCount.Component | null;
|
|
351
|
+
ChatListItemLastMessage?: typeof ChatListItemLastMessage.Component | null;
|
|
352
|
+
ChatListItemLastMessageAuthor?: typeof ChatListItemLastMessageAuthor.Component | null;
|
|
353
|
+
ChatListItemLastMessageContent?: typeof ChatListItemLastMessageContent.Component | null;
|
|
354
|
+
SendingMessage?: typeof SendingMessage.Component | null;
|
|
355
|
+
SendingMessageBody?: typeof SendingMessageBody.Component | null;
|
|
356
|
+
SendingMessageInfoBox?: typeof SendingMessageInfoBox.Component | null;
|
|
357
|
+
SendingMessageText?: typeof SendingMessageText.Component | null;
|
|
358
|
+
Message?: typeof Message.Component | null;
|
|
359
|
+
MessageReadObserver?: typeof MessageReadObserver.Component | null;
|
|
360
|
+
MessageBox?: typeof MessageBox.Component | null;
|
|
361
|
+
MessageBody?: typeof MessageBody.Component | null;
|
|
362
|
+
MessageInfoBox?: typeof MessageInfoBox.Component | null;
|
|
363
|
+
MessageText?: typeof MessageText.Component | null;
|
|
364
|
+
MessageAuthor?: typeof MessageAuthor.Component | null;
|
|
306
365
|
}
|
|
307
366
|
interface ChatifyProps {
|
|
308
367
|
className?: string;
|
|
@@ -327,4 +386,4 @@ declare function ChatifyContext({ value, children }: PropsWithChildren<{
|
|
|
327
386
|
value: ChatifyContextValue;
|
|
328
387
|
}>): react_jsx_runtime.JSX.Element;
|
|
329
388
|
|
|
330
|
-
export { ACTIONS, Account, Action, AddChatButton, AddChatRequest, AddMemberRequest, Avatar, AvatarProps, Chat, ChatHeader, ChatHeaderMembers, ChatHeaderMembersProps, ChatHeaderProps, ChatListItem, Chatify, ChatifyClient, ChatifyClientConfig, ChatifyContext, ChatifyContextValue, ChatifyCustomizeValue, ChatifyProps, ChatifySignalRConfig, File, Header, Localizer, LocalizerContext, Message, MessageContent, MessageState, ReadEvent, ReadRequest, Reducer, ReducerProvider, RemoveMemberRequest, SendMessageRequest, defaultLocalizer, useAccounts, useAddChat, useAddMember, useChat, useChatList, useClient, useDispatch, useLoadMore, useLocalizer, useMe, useMessages, useReadMonitor, useReducer, useRemoveMember, useSelect, useSignalRMonitor, useStateRef };
|
|
389
|
+
export { ACTIONS, Account, Action, AddChatButton, AddChatRequest, AddMemberRequest, Avatar, AvatarProps, Chat, ChatHeader, ChatHeaderMembers, ChatHeaderMembersProps, ChatHeaderProps, ChatListItem, ChatListItemLastMessage, ChatListItemLastMessageAuthor, ChatListItemLastMessageContent, ChatListItemName, ChatListItemProps, ChatListItemUnreadCount, ChatListItemView, Chatify, ChatifyClient, ChatifyClientConfig, ChatifyContext, ChatifyContextValue, ChatifyCustomizeValue, ChatifyProps, ChatifySignalRConfig, File, Header, Localizer, LocalizerContext, Message$1 as Message, MessageContent, MessageState, ReadEvent, ReadRequest, Reducer, ReducerProvider, RemoveMemberRequest, SendMessageRequest, defaultLocalizer, useAccounts, useAddChat, useAddMember, useChat, useChatList, useClient, useDispatch, useLoadMore, useLocalizer, useMe, useMessages, useReadMonitor, useReducer, useRemoveMember, useSelect, useSignalRMonitor, useStateRef };
|
package/package.json
CHANGED
package/src/core/reducer.tsx
CHANGED
|
@@ -19,7 +19,7 @@ export function useReducer() {
|
|
|
19
19
|
|
|
20
20
|
const dispatch = useCallback((action: Action) => {
|
|
21
21
|
const newState = reducer(state.current, action);
|
|
22
|
-
if (
|
|
22
|
+
if (state.current === newState) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -63,7 +63,13 @@ export function useSelect<TResult>(
|
|
|
63
63
|
const [state, setState] = useState(prev.current);
|
|
64
64
|
|
|
65
65
|
useEffect(() => {
|
|
66
|
-
|
|
66
|
+
const value = select(reducerState.current);
|
|
67
|
+
if (!shallowEqual<any>(prev.current, value)) {
|
|
68
|
+
prev.current = value;
|
|
69
|
+
setState(value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return subscribe((state: State) => {
|
|
67
73
|
const newValue = select(state);
|
|
68
74
|
if (shallowEqual<any>(newValue, prev.current)) {
|
|
69
75
|
return;
|
package/src/ui/Aside.tsx
CHANGED
|
@@ -1,35 +1,8 @@
|
|
|
1
1
|
import { Menu, MenuProps } from 'antd';
|
|
2
2
|
import { useCallback, useEffect, useMemo } from 'react';
|
|
3
3
|
import type { MenuItemType } from 'antd/es/menu/hooks/useItems';
|
|
4
|
-
import { useChatList, useDispatch, useSelect
|
|
5
|
-
import {
|
|
6
|
-
import { formatSystemMessage } from './SystemMessage';
|
|
7
|
-
import { Avatar } from './Avatar';
|
|
8
|
-
|
|
9
|
-
function Chat(props: { chat: ChatListItem }) {
|
|
10
|
-
const { chat } = props;
|
|
11
|
-
const { name, message, unreadCount } = chat;
|
|
12
|
-
const localizer = useLocalizer();
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<div className={'wxchtf-chat' + (!message.read ? ' --unread' : '')}>
|
|
16
|
-
<div className="wxchtf-chat-name">{name}</div>
|
|
17
|
-
{unreadCount > 0 && <div className="wxchtf-unread-count">{unreadCount}</div>}
|
|
18
|
-
<div className="wxchtf-chat-last">
|
|
19
|
-
{message.sentBy.id !== 'chatify::system' && (
|
|
20
|
-
<div className="wxchtf-chat-last-author">
|
|
21
|
-
<Avatar account={message.sentBy} /> {message.sentBy.name}
|
|
22
|
-
</div>
|
|
23
|
-
)}
|
|
24
|
-
<div className="wxchtf-chat-last-message">
|
|
25
|
-
{message.sentBy.id === 'chatify::system'
|
|
26
|
-
? formatSystemMessage(localizer, message.text)
|
|
27
|
-
: message.text}
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
4
|
+
import { useChatList, useDispatch, useSelect } from '../core';
|
|
5
|
+
import { ChatListItemView } from './ChatListItem';
|
|
33
6
|
|
|
34
7
|
export function Aside() {
|
|
35
8
|
const activeChatId = useSelect((x) => x.ui.chatId, []);
|
|
@@ -49,7 +22,7 @@ export function Aside() {
|
|
|
49
22
|
return [];
|
|
50
23
|
}
|
|
51
24
|
|
|
52
|
-
return chats.map((x) => ({ key: x.id, label: <
|
|
25
|
+
return chats.map((x) => ({ key: x.id, label: <ChatListItemView chat={x} /> }));
|
|
53
26
|
}, [chats]);
|
|
54
27
|
|
|
55
28
|
useEffect(() => {
|
package/src/ui/ChatHeader.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { useChat, useSelect, ChatListItem } from '../core';
|
|
|
2
2
|
import { Col, Row, Space } from 'antd';
|
|
3
3
|
import { ChatHeaderMembers } from './ChatHeaderMembers';
|
|
4
4
|
import { ChatSettingsButton } from './ChatHeaderSettingsButton';
|
|
5
|
+
import { ChatName } from './ChatName';
|
|
5
6
|
|
|
6
7
|
export interface ChatHeaderProps {
|
|
7
8
|
id: string;
|
|
@@ -14,11 +15,12 @@ export function ChatHeader(props: ChatHeaderProps) {
|
|
|
14
15
|
(x) => x.query['chat-list'].data?.find((x: ChatListItem) => x.id === id),
|
|
15
16
|
[id],
|
|
16
17
|
);
|
|
18
|
+
const name = chat?.name ?? chatListItem?.name;
|
|
17
19
|
|
|
18
20
|
return (
|
|
19
21
|
<div className="wxchtf-chat-header">
|
|
20
22
|
<Row justify="space-between" align="middle">
|
|
21
|
-
<Col className="wxchtf-chat-name">{
|
|
23
|
+
<Col className="wxchtf-chat-name">{name && <ChatName name={name} />}</Col>
|
|
22
24
|
<Col className="wxchtf-chat-members">
|
|
23
25
|
<Space align="center">
|
|
24
26
|
<ChatHeaderMembers id={id} />
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { useLocalizer } from './localizer';
|
|
2
|
+
import { formatSystemMessage } from './SystemMessage';
|
|
3
|
+
import { Avatar } from './Avatar';
|
|
4
|
+
import { ChatName } from './ChatName';
|
|
5
|
+
import { ChatListItem as ChatListItemModel } from '../core';
|
|
6
|
+
import { FC } from 'react';
|
|
7
|
+
import { customize } from '../util';
|
|
8
|
+
|
|
9
|
+
export interface ChatListItemProps {
|
|
10
|
+
chat: ChatListItemModel;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const _ChatListItemName: FC<ChatListItemProps> = (props) => {
|
|
14
|
+
const { name } = props.chat;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className="wxchtf-chat-name">
|
|
18
|
+
<ChatName name={name} />
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
_ChatListItemName.displayName = 'ChatListItemName';
|
|
24
|
+
|
|
25
|
+
export const ChatListItemName = customize('ChatListItemName', _ChatListItemName);
|
|
26
|
+
|
|
27
|
+
const _ChatListItemUnreadCount: FC<ChatListItemProps> = (props) => {
|
|
28
|
+
const { unreadCount } = props.chat;
|
|
29
|
+
|
|
30
|
+
if (unreadCount <= 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return <div className="wxchtf-unread-count">{unreadCount}</div>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
_ChatListItemUnreadCount.displayName = 'ChatListItemUnreadCount';
|
|
38
|
+
|
|
39
|
+
export const ChatListItemUnreadCount = customize('ChatListItemUnreadCount', _ChatListItemUnreadCount);
|
|
40
|
+
|
|
41
|
+
const _ChatListItemLastMessage: FC<ChatListItemProps> = (props) => {
|
|
42
|
+
return (
|
|
43
|
+
<div className="wxchtf-chat-last">
|
|
44
|
+
<ChatListItemLastMessageAuthor {...props} />
|
|
45
|
+
<ChatListItemLastMessageContent {...props} />
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
_ChatListItemLastMessage.displayName = 'ChatListItemLastMessage';
|
|
51
|
+
|
|
52
|
+
export const ChatListItemLastMessage = customize('ChatListItemLastMessage', _ChatListItemLastMessage);
|
|
53
|
+
|
|
54
|
+
export const ChatListItemLastMessageAuthor = customize<FC<ChatListItemProps>, string>(
|
|
55
|
+
'ChatListItemLastMessageAuthor',
|
|
56
|
+
(props) => {
|
|
57
|
+
const { message } = props.chat;
|
|
58
|
+
|
|
59
|
+
if (message.sentBy.id === 'chatify::system') {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="wxchtf-chat-last-author">
|
|
65
|
+
<Avatar account={message.sentBy} /> {message.sentBy.name}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export const ChatListItemLastMessageContent = customize<FC<ChatListItemProps>, string>(
|
|
72
|
+
'ChatListItemLastMessageContent',
|
|
73
|
+
(props) => {
|
|
74
|
+
const { message } = props.chat;
|
|
75
|
+
const localizer = useLocalizer();
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className="wxchtf-chat-last-message">
|
|
79
|
+
{message.sentBy.id === 'chatify::system'
|
|
80
|
+
? formatSystemMessage(localizer, message.text)
|
|
81
|
+
: message.text}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const _ChatListItem: FC<ChatListItemProps> = (props) => {
|
|
88
|
+
const { message } = props.chat;
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div className={'wxchtf-chat' + (!message.read ? ' --unread' : '')}>
|
|
92
|
+
<ChatListItemName {...props} />
|
|
93
|
+
<ChatListItemUnreadCount {...props} />
|
|
94
|
+
<ChatListItemLastMessage {...props} />
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
_ChatListItem.displayName = 'ChatListItem';
|
|
100
|
+
|
|
101
|
+
export const ChatListItemView = customize('ChatListItemView', _ChatListItem);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { customize } from '../util';
|
|
3
|
+
|
|
4
|
+
export interface ChatNameProps {
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const _ChatName: FC<ChatNameProps> = (props) => {
|
|
9
|
+
const { name } = props;
|
|
10
|
+
return <>{name}</>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
_ChatName.displayName = 'ChatName';
|
|
14
|
+
|
|
15
|
+
export const ChatName = customize('ChatName', _ChatName);
|
package/src/ui/Chatify.tsx
CHANGED
|
@@ -10,6 +10,30 @@ import { ChatSettingsButton } from './ChatHeaderSettingsButton';
|
|
|
10
10
|
import { Header } from './Header';
|
|
11
11
|
import { AddChatButton } from './AddChatButton';
|
|
12
12
|
import { Footer } from './Footer';
|
|
13
|
+
import { ChatName } from './ChatName';
|
|
14
|
+
import {
|
|
15
|
+
ChatListItemView,
|
|
16
|
+
ChatListItemLastMessage,
|
|
17
|
+
ChatListItemLastMessageAuthor,
|
|
18
|
+
ChatListItemLastMessageContent,
|
|
19
|
+
ChatListItemName,
|
|
20
|
+
ChatListItemUnreadCount,
|
|
21
|
+
} from './ChatListItem';
|
|
22
|
+
import {
|
|
23
|
+
SendingMessage,
|
|
24
|
+
SendingMessageBody,
|
|
25
|
+
SendingMessageInfoBox,
|
|
26
|
+
SendingMessageText,
|
|
27
|
+
} from './SendingMessage';
|
|
28
|
+
import {
|
|
29
|
+
Message,
|
|
30
|
+
MessageAuthor,
|
|
31
|
+
MessageBody,
|
|
32
|
+
MessageBox,
|
|
33
|
+
MessageInfoBox,
|
|
34
|
+
MessageReadObserver,
|
|
35
|
+
MessageText,
|
|
36
|
+
} from './Message';
|
|
13
37
|
|
|
14
38
|
export interface ChatifyCustomizeValue {
|
|
15
39
|
Avatar?: typeof Avatar.Component | null;
|
|
@@ -18,6 +42,24 @@ export interface ChatifyCustomizeValue {
|
|
|
18
42
|
AddChatButton?: typeof AddChatButton.Component | null;
|
|
19
43
|
ChatHeaderMembers?: typeof ChatHeaderMembers.Component | null;
|
|
20
44
|
ChatSettingsButton?: typeof ChatSettingsButton.Component | null;
|
|
45
|
+
ChatName?: typeof ChatName.Component | null;
|
|
46
|
+
ChatListItem?: typeof ChatListItemView.Component | null;
|
|
47
|
+
ChatListItemName?: typeof ChatListItemName.Component | null;
|
|
48
|
+
ChatListItemUnreadCount?: typeof ChatListItemUnreadCount.Component | null;
|
|
49
|
+
ChatListItemLastMessage?: typeof ChatListItemLastMessage.Component | null;
|
|
50
|
+
ChatListItemLastMessageAuthor?: typeof ChatListItemLastMessageAuthor.Component | null;
|
|
51
|
+
ChatListItemLastMessageContent?: typeof ChatListItemLastMessageContent.Component | null;
|
|
52
|
+
SendingMessage?: typeof SendingMessage.Component | null;
|
|
53
|
+
SendingMessageBody?: typeof SendingMessageBody.Component | null;
|
|
54
|
+
SendingMessageInfoBox?: typeof SendingMessageInfoBox.Component | null;
|
|
55
|
+
SendingMessageText?: typeof SendingMessageText.Component | null;
|
|
56
|
+
Message?: typeof Message.Component | null;
|
|
57
|
+
MessageReadObserver?: typeof MessageReadObserver.Component | null;
|
|
58
|
+
MessageBox?: typeof MessageBox.Component | null;
|
|
59
|
+
MessageBody?: typeof MessageBody.Component | null;
|
|
60
|
+
MessageInfoBox?: typeof MessageInfoBox.Component | null;
|
|
61
|
+
MessageText?: typeof MessageText.Component | null;
|
|
62
|
+
MessageAuthor?: typeof MessageAuthor.Component | null;
|
|
21
63
|
}
|
|
22
64
|
|
|
23
65
|
export interface ChatifyProps {
|
package/src/ui/Message.tsx
CHANGED
|
@@ -1,50 +1,117 @@
|
|
|
1
1
|
import { useMe } from '../ChatifyContext';
|
|
2
|
-
import {
|
|
3
|
-
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { FC, Ref, RefObject, useEffect, useMemo, useRef } from 'react';
|
|
4
3
|
import { useDispatch, useSelect, Message as MessageModel } from '../core';
|
|
4
|
+
import { customize } from '../util';
|
|
5
|
+
import { useLocalizer } from './localizer';
|
|
6
|
+
import { Avatar } from './Avatar';
|
|
5
7
|
|
|
6
8
|
export interface MessageProps {
|
|
7
9
|
message: MessageModel;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
export
|
|
12
|
+
export interface MessageBoxProps extends MessageProps {
|
|
13
|
+
containerRef?: Ref<HTMLDivElement>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const MessageAuthor = customize<FC<MessageProps>, string>('MessageAuthor', (props) => {
|
|
17
|
+
const { sentBy } = props.message;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="wxchtf-message-author">
|
|
21
|
+
<Avatar account={sentBy} />
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const MessageText = customize<FC<MessageProps>, string>('MessageText', (props) => {
|
|
27
|
+
const { text } = props.message;
|
|
28
|
+
return <div className="wxchtf-message-text">{text}</div>;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const MessageInfoBox = customize<FC<MessageProps>, string>('MessageInfoBox', (props) => {
|
|
11
32
|
const { message } = props;
|
|
33
|
+
const { id, sentBy, sentAt, read } = message;
|
|
12
34
|
const me = useMe();
|
|
13
|
-
const my =
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}),
|
|
27
|
-
|
|
28
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
29
|
-
[],
|
|
35
|
+
const my = sentBy.id === me;
|
|
36
|
+
const localizer = useLocalizer();
|
|
37
|
+
const reading = useSelect((x) => x.read.queued.includes(id), []);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="wxchtf-message-info-box">
|
|
41
|
+
<div className="wxchtf-message-sent-at">{localizer.timestamp(sentAt)}</div>
|
|
42
|
+
{read !== undefined && !my && (
|
|
43
|
+
<div className="wxchtf-message-read-box">
|
|
44
|
+
{reading ? localizer.message.reading() : localizer.message.read()}
|
|
45
|
+
</div>
|
|
46
|
+
)}
|
|
47
|
+
</div>
|
|
30
48
|
);
|
|
49
|
+
});
|
|
31
50
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
export const MessageBody = customize<FC<MessageProps>, string>('MessageBody', (props) => {
|
|
52
|
+
return (
|
|
53
|
+
<div className="wxchtf-message-body">
|
|
54
|
+
<MessageText {...props} />
|
|
55
|
+
<MessageInfoBox {...props} />
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const MessageBox = customize<FC<MessageBoxProps>, string>('MessageBox', (props) => {
|
|
61
|
+
const { message, containerRef } = props;
|
|
62
|
+
const { sentBy } = message;
|
|
63
|
+
const me = useMe();
|
|
64
|
+
const my = sentBy.id === me;
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div ref={containerRef} className={'wxchtf-message' + (my ? ' --my' : '')}>
|
|
68
|
+
<MessageAuthor {...props} />
|
|
69
|
+
<MessageBody {...props} />
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const Message = customize<FC<MessageProps>, string>('Message', (props) => {
|
|
75
|
+
const ref = useRef<HTMLDivElement | null>(null);
|
|
36
76
|
|
|
37
77
|
return (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
files={message.files}
|
|
43
|
-
author={message.sentBy}
|
|
44
|
-
timestamp={message.sentAt}
|
|
45
|
-
read={message.read}
|
|
46
|
-
sending={false}
|
|
47
|
-
reading={reading}
|
|
48
|
-
/>
|
|
78
|
+
<>
|
|
79
|
+
<MessageReadObserver messageRef={ref} {...props} />
|
|
80
|
+
<MessageBox containerRef={ref} {...props} />
|
|
81
|
+
</>
|
|
49
82
|
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export interface MessageReadObserverProps extends MessageProps {
|
|
86
|
+
messageRef: RefObject<HTMLDivElement | null>;
|
|
50
87
|
}
|
|
88
|
+
export const MessageReadObserver = customize<FC<MessageReadObserverProps>, string>(
|
|
89
|
+
'MessageReadObserver',
|
|
90
|
+
(props) => {
|
|
91
|
+
const { message, messageRef } = props;
|
|
92
|
+
const dispatch = useDispatch();
|
|
93
|
+
const readRef = useRef(false);
|
|
94
|
+
|
|
95
|
+
const observer = useMemo(
|
|
96
|
+
() =>
|
|
97
|
+
new IntersectionObserver(([entry]) => {
|
|
98
|
+
if (entry.isIntersecting && !readRef.current && !message.read) {
|
|
99
|
+
readRef.current = true;
|
|
100
|
+
dispatch({ type: 'read', data: { id: message.id, timestamp: new Date().getTime() } });
|
|
101
|
+
}
|
|
102
|
+
}),
|
|
103
|
+
|
|
104
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
105
|
+
[],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
observer.observe(messageRef.current!);
|
|
110
|
+
return () => observer.disconnect();
|
|
111
|
+
|
|
112
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
113
|
+
}, [observer]);
|
|
114
|
+
|
|
115
|
+
return <></>;
|
|
116
|
+
},
|
|
117
|
+
);
|
|
@@ -1,14 +1,50 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
1
2
|
import { File } from '../core';
|
|
2
|
-
import {
|
|
3
|
+
import { customize } from '../util';
|
|
4
|
+
import { useLocalizer } from './localizer';
|
|
3
5
|
|
|
4
6
|
export interface SendingMessageProps {
|
|
5
7
|
text: string;
|
|
6
8
|
files: File[];
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
+
export const SendingMessageText = customize<FC<SendingMessageProps>, string>(
|
|
12
|
+
'SendingMessageText',
|
|
13
|
+
(props) => {
|
|
14
|
+
const { text } = props;
|
|
15
|
+
return <div className="wxchtf-sending-message-text">{text}</div>;
|
|
16
|
+
},
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const SendingMessageInfoBox = customize<FC<SendingMessageProps>, string>(
|
|
20
|
+
'SendingMessageInfoBox',
|
|
21
|
+
() => {
|
|
22
|
+
const localizer = useLocalizer();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="wxchtf-sending-message-info-box">
|
|
26
|
+
<div className="wxchtf-sending-message-sending-box">{localizer.message.sending()}</div>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const SendingMessageBody = customize<FC<SendingMessageProps>, string>(
|
|
33
|
+
'SendingMessageBody',
|
|
34
|
+
(props) => {
|
|
35
|
+
return (
|
|
36
|
+
<div className="wxchtf-sending-message-body">
|
|
37
|
+
<SendingMessageText {...props} />
|
|
38
|
+
<SendingMessageInfoBox {...props} />
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const SendingMessage = customize<FC<SendingMessageProps>, string>('SendingMessage', (props) => {
|
|
11
45
|
return (
|
|
12
|
-
<
|
|
46
|
+
<div className="wxchtf-sending-message">
|
|
47
|
+
<SendingMessageBody {...props} />
|
|
48
|
+
</div>
|
|
13
49
|
);
|
|
14
|
-
}
|
|
50
|
+
});
|
package/src/ui/index.ts
CHANGED