@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.
@@ -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';
@@ -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
@@ -2,7 +2,7 @@
2
2
  "name": "@webinex/chatify",
3
3
  "description": "Webinex Wispo",
4
4
  "private": false,
5
- "version": "1.0.0-alpha03",
5
+ "version": "1.0.0-alpha05",
6
6
  "author": "Webinex Dev",
7
7
  "license": "Apache-2.0",
8
8
  "main": "dist/cjs/index.js",
@@ -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 (shallowEqual(state.current, newState)) {
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
- return subscribe((state) => {
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, ChatListItem } from '../core';
5
- import { useLocalizer } from './localizer';
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: <Chat chat={x} /> }));
25
+ return chats.map((x) => ({ key: x.id, label: <ChatListItemView chat={x} /> }));
53
26
  }, [chats]);
54
27
 
55
28
  useEffect(() => {
@@ -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">{chat?.name ?? chatListItem?.name}</Col>
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);
@@ -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 {
@@ -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';