@webinex/chatify 1.0.0-alpha04 → 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.
@@ -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 declare function Message(props: MessageProps): import("react/jsx-runtime").JSX.Element;
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 function SendingMessage(props: SendingMessageProps): import("react/jsx-runtime").JSX.Element;
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>;
@@ -5,3 +5,4 @@ export * from './AddChatButton';
5
5
  export * from './Header';
6
6
  export * from './ChatHeader';
7
7
  export * from './ChatHeaderMembers';
8
+ export * from './ChatListItem';
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';
@@ -301,6 +301,42 @@ interface ChatNameProps {
301
301
  }
302
302
  declare const ChatName: Customizable<FC<ChatNameProps>, "ChatName">;
303
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
+
304
340
  interface ChatifyCustomizeValue {
305
341
  Avatar?: typeof Avatar.Component | null;
306
342
  Header?: typeof Header.Component | null;
@@ -309,6 +345,23 @@ interface ChatifyCustomizeValue {
309
345
  ChatHeaderMembers?: typeof ChatHeaderMembers.Component | null;
310
346
  ChatSettingsButton?: typeof ChatSettingsButton.Component | null;
311
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;
312
365
  }
313
366
  interface ChatifyProps {
314
367
  className?: string;
@@ -333,4 +386,4 @@ declare function ChatifyContext({ value, children }: PropsWithChildren<{
333
386
  value: ChatifyContextValue;
334
387
  }>): react_jsx_runtime.JSX.Element;
335
388
 
336
- 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
@@ -2,7 +2,7 @@
2
2
  "name": "@webinex/chatify",
3
3
  "description": "Webinex Wispo",
4
4
  "private": false,
5
- "version": "1.0.0-alpha04",
5
+ "version": "1.0.0-alpha05",
6
6
  "author": "Webinex Dev",
7
7
  "license": "Apache-2.0",
8
8
  "main": "dist/cjs/index.js",
package/src/ui/Aside.tsx CHANGED
@@ -1,38 +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, ChatListItem } from '../core';
5
- import { useLocalizer } from './localizer';
6
- import { formatSystemMessage } from './SystemMessage';
7
- import { Avatar } from './Avatar';
8
- import { ChatName } from './ChatName';
9
-
10
- function Chat(props: { chat: ChatListItem }) {
11
- const { chat } = props;
12
- const { name, message, unreadCount } = chat;
13
- const localizer = useLocalizer();
14
-
15
- return (
16
- <div className={'wxchtf-chat' + (!message.read ? ' --unread' : '')}>
17
- <div className="wxchtf-chat-name">
18
- <ChatName name={name} />
19
- </div>
20
- {unreadCount > 0 && <div className="wxchtf-unread-count">{unreadCount}</div>}
21
- <div className="wxchtf-chat-last">
22
- {message.sentBy.id !== 'chatify::system' && (
23
- <div className="wxchtf-chat-last-author">
24
- <Avatar account={message.sentBy} /> {message.sentBy.name}
25
- </div>
26
- )}
27
- <div className="wxchtf-chat-last-message">
28
- {message.sentBy.id === 'chatify::system'
29
- ? formatSystemMessage(localizer, message.text)
30
- : message.text}
31
- </div>
32
- </div>
33
- </div>
34
- );
35
- }
4
+ import { useChatList, useDispatch, useSelect } from '../core';
5
+ import { ChatListItemView } from './ChatListItem';
36
6
 
37
7
  export function Aside() {
38
8
  const activeChatId = useSelect((x) => x.ui.chatId, []);
@@ -52,7 +22,7 @@ export function Aside() {
52
22
  return [];
53
23
  }
54
24
 
55
- return chats.map((x) => ({ key: x.id, label: <Chat chat={x} /> }));
25
+ return chats.map((x) => ({ key: x.id, label: <ChatListItemView chat={x} /> }));
56
26
  }, [chats]);
57
27
 
58
28
  useEffect(() => {
@@ -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);
@@ -11,6 +11,29 @@ import { Header } from './Header';
11
11
  import { AddChatButton } from './AddChatButton';
12
12
  import { Footer } from './Footer';
13
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';
14
37
 
15
38
  export interface ChatifyCustomizeValue {
16
39
  Avatar?: typeof Avatar.Component | null;
@@ -20,6 +43,23 @@ export interface ChatifyCustomizeValue {
20
43
  ChatHeaderMembers?: typeof ChatHeaderMembers.Component | null;
21
44
  ChatSettingsButton?: typeof ChatSettingsButton.Component | null;
22
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;
23
63
  }
24
64
 
25
65
  export interface ChatifyProps {
@@ -1,50 +1,117 @@
1
1
  import { useMe } from '../ChatifyContext';
2
- import { MessageMd } from './MessageMd';
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 function Message(props: MessageProps) {
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 = message.sentBy.id === me;
14
- const dispatch = useDispatch();
15
- const ref = useRef<HTMLDivElement | null>(null);
16
- const readRef = useRef(false);
17
- const reading = useSelect((x) => x.read.queued.includes(message.id), []);
18
-
19
- const observer = useMemo(
20
- () =>
21
- new IntersectionObserver(([entry]) => {
22
- if (entry.isIntersecting && !readRef.current && !message.read) {
23
- readRef.current = true;
24
- dispatch({ type: 'read', data: { id: message.id, timestamp: new Date().getTime() } });
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
- useEffect(() => {
33
- observer.observe(ref.current!);
34
- return () => observer.disconnect();
35
- }, [observer]);
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
- <MessageMd
39
- ref={ref}
40
- my={my}
41
- text={message.text}
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 { MessageMd } from './MessageMd';
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 function SendingMessage(props: SendingMessageProps) {
10
- const { text, files } = props;
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
- <MessageMd text={text} files={files} my={true} sending={true} timestamp={new Date().toUTCString()} />
46
+ <div className="wxchtf-sending-message">
47
+ <SendingMessageBody {...props} />
48
+ </div>
13
49
  );
14
- }
50
+ });
package/src/ui/index.ts CHANGED
@@ -5,3 +5,4 @@ export * from './AddChatButton';
5
5
  export * from './Header';
6
6
  export * from './ChatHeader';
7
7
  export * from './ChatHeaderMembers';
8
+ export * from './ChatListItem';
@@ -62,7 +62,8 @@
62
62
  padding-right: 30%;
63
63
  }
64
64
 
65
- .wxchtf-message {
65
+ .wxchtf-message,
66
+ .wxchtf-sending-message {
66
67
  display: flex;
67
68
  flex-flow: row nowrap;
68
69
  width: 100%;
@@ -81,7 +82,8 @@
81
82
  margin-left: 15px;
82
83
  }
83
84
 
84
- .wxchtf-message-body {
85
+ .wxchtf-message-body,
86
+ .wxchtf-sending-message-body {
85
87
  direction: ltr;
86
88
  border-bottom-left-radius: 10px;
87
89
  border-bottom-right-radius: 0;
@@ -98,7 +100,8 @@
98
100
  }
99
101
  }
100
102
 
101
- .wxchtf-message-body {
103
+ .wxchtf-message-body,
104
+ .wxchtf-sending-message-body {
102
105
  min-width: 300px;
103
106
  max-width: 70%;
104
107
  border-radius: $messageBorderRadius;
@@ -111,12 +114,13 @@
111
114
  white-space: pre-wrap;
112
115
  overflow-wrap: break-word;
113
116
 
114
- .wxchtf-message-info-box {
117
+ .wxchtf-message-info-box,
118
+ .wxchtf-sending-message-info-box {
115
119
  text-align: right;
116
120
 
117
121
  .wxchtf-message-sent-at,
118
122
  .wxchtf-message-read-box,
119
- .wxchtf-message-sending-box {
123
+ .wxchtf-sending-message-sending-box {
120
124
  display: inline-block;
121
125
  font-style: italic;
122
126
  font-size: 0.75em;
@@ -125,7 +129,7 @@
125
129
  }
126
130
 
127
131
  .wxchtf-message-read-box,
128
- .wxchtf-message-sending-box {
132
+ .wxchtf-sending-message-sending-box {
129
133
  margin-left: 5px;
130
134
  }
131
135
  }
@@ -150,6 +154,7 @@
150
154
  }
151
155
 
152
156
  .wxchtf-message,
157
+ .wxchtf-sending-message,
153
158
  .wxchtf-system-message,
154
159
  .wxchtf-message-skeleton {
155
160
  margin-bottom: 2rem;
@@ -1,13 +0,0 @@
1
- import { Account, File } from '../core';
2
- import React from 'react';
3
- export interface MessageMdProps {
4
- author?: Account;
5
- text: string;
6
- files: File[];
7
- my: boolean;
8
- read?: boolean;
9
- sending?: boolean;
10
- reading?: boolean;
11
- timestamp: string;
12
- }
13
- export declare const MessageMd: React.ForwardRefExoticComponent<MessageMdProps & React.RefAttributes<HTMLDivElement>>;