@webinex/chatify 1.0.0-rc2 → 1.0.1-rc3

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.
Files changed (273) hide show
  1. package/dist/css/chatify.css +183 -141
  2. package/dist/esm/index.js +1 -1
  3. package/dist/esm/index.js.map +1 -1
  4. package/dist/esm/types/core/action.d.ts +110 -42
  5. package/dist/esm/types/core/client.d.ts +2 -1
  6. package/dist/esm/types/core/index.d.ts +11 -8
  7. package/dist/esm/types/core/models.d.ts +10 -4
  8. package/dist/esm/types/core/state.d.ts +36 -7
  9. package/dist/esm/types/core/useAddChatMutation.d.ts +2 -0
  10. package/dist/esm/types/core/useAddMemberMutation.d.ts +2 -0
  11. package/dist/esm/types/core/useFetchNextMutation.d.ts +3 -0
  12. package/dist/esm/types/core/useGetAccountsQuery.d.ts +1 -0
  13. package/dist/esm/types/core/useGetChatListQuery.d.ts +1 -0
  14. package/dist/{cjs/types/core/useChat.d.ts → esm/types/core/useGetChatQuery.d.ts} +1 -1
  15. package/dist/esm/types/core/useGetMessagesQuery.d.ts +4 -0
  16. package/dist/esm/types/core/useRemoveMemberMutation.d.ts +2 -0
  17. package/dist/esm/types/core/useSendMutation.d.ts +2 -0
  18. package/dist/esm/types/core/useUpdateChatNameMutation.d.ts +2 -0
  19. package/dist/esm/types/ui/AddChatButton.d.ts +2 -2
  20. package/dist/esm/types/ui/Avatar.d.ts +2 -2
  21. package/dist/esm/types/ui/ChatList/ChatList.d.ts +2 -0
  22. package/dist/esm/types/ui/ChatList/ChatListItemBox.d.ts +6 -0
  23. package/dist/esm/types/ui/ChatList/ChatListItemLastMessage.d.ts +3 -0
  24. package/dist/esm/types/ui/ChatList/ChatListItemLastMessageAuthor.d.ts +3 -0
  25. package/dist/esm/types/ui/ChatList/ChatListItemLastMessageContent.d.ts +3 -0
  26. package/dist/esm/types/ui/ChatList/ChatListItemName.d.ts +3 -0
  27. package/dist/esm/types/ui/ChatList/ChatListItemUnreadCount.d.ts +3 -0
  28. package/dist/esm/types/ui/ChatList/index.d.ts +7 -0
  29. package/dist/esm/types/ui/ChatName.d.ts +2 -2
  30. package/dist/esm/types/ui/ChatPanel/ChatBody.d.ts +5 -0
  31. package/dist/esm/types/ui/ChatPanel/ChatHeader.d.ts +5 -0
  32. package/dist/esm/types/ui/ChatPanel/ChatHeaderMembers.d.ts +5 -0
  33. package/dist/esm/types/ui/ChatPanel/ChatHeaderName.d.ts +5 -0
  34. package/dist/esm/types/ui/ChatPanel/ChatMembersButton.d.ts +5 -0
  35. package/dist/esm/types/ui/ChatPanel/ChatMembersPanel.d.ts +5 -0
  36. package/dist/esm/types/ui/ChatPanel/ChatPanel.d.ts +5 -0
  37. package/dist/esm/types/ui/ChatPanel/index.d.ts +6 -0
  38. package/dist/esm/types/ui/Chatify.d.ts +45 -23
  39. package/dist/esm/types/ui/CreateChatPanel/CreateChatForm.d.ts +11 -0
  40. package/dist/esm/types/ui/CreateChatPanel/CreateChatMemberInput.d.ts +5 -0
  41. package/dist/esm/types/ui/CreateChatPanel/CreateChatNameInput.d.ts +5 -0
  42. package/dist/esm/types/ui/CreateChatPanel/CreateChatPanel.d.ts +2 -0
  43. package/dist/esm/types/ui/CreateChatPanel/index.d.ts +4 -0
  44. package/dist/esm/types/ui/Icon.d.ts +13 -4
  45. package/dist/esm/types/ui/InputBox/InputBox.d.ts +2 -0
  46. package/dist/esm/types/ui/InputBox/InputFilesBox.d.ts +2 -0
  47. package/dist/esm/types/ui/InputBox/InputSubmitButtonBox.d.ts +5 -0
  48. package/dist/esm/types/ui/InputBox/InputTextBox.d.ts +7 -0
  49. package/dist/esm/types/ui/InputBox/index.d.ts +4 -0
  50. package/dist/esm/types/ui/Layout/Aside.d.ts +2 -0
  51. package/dist/esm/types/ui/Layout/Body.d.ts +2 -0
  52. package/dist/esm/types/ui/Layout/Footer.d.ts +2 -0
  53. package/dist/esm/types/ui/Layout/Header.d.ts +2 -0
  54. package/dist/esm/types/ui/Layout/Main.d.ts +2 -0
  55. package/dist/esm/types/ui/Layout/index.d.ts +5 -0
  56. package/dist/esm/types/ui/Message/MessageAuthor.d.ts +3 -0
  57. package/dist/esm/types/ui/Message/MessageBox.d.ts +6 -0
  58. package/dist/esm/types/ui/Message/MessageContent.d.ts +3 -0
  59. package/dist/esm/types/ui/Message/MessageInfoBox.d.ts +3 -0
  60. package/dist/esm/types/ui/Message/MessageRow.d.ts +6 -0
  61. package/dist/esm/types/ui/Message/MessageText.d.ts +3 -0
  62. package/dist/esm/types/ui/Message/index.d.ts +6 -0
  63. package/dist/esm/types/ui/MessageReadObserver.d.ts +6 -0
  64. package/dist/esm/types/ui/Next.d.ts +4 -0
  65. package/dist/esm/types/ui/SendingMessage/SendingMessageBox.d.ts +7 -0
  66. package/dist/esm/types/ui/SendingMessage/SendingMessageContent.d.ts +3 -0
  67. package/dist/esm/types/ui/SendingMessage/SendingMessageInfoBox.d.ts +3 -0
  68. package/dist/esm/types/ui/SendingMessage/SendingMessageText.d.ts +3 -0
  69. package/dist/esm/types/ui/SendingMessage/index.d.ts +4 -0
  70. package/dist/esm/types/ui/SystemMessage/SystemMessageBox.d.ts +6 -0
  71. package/dist/esm/types/ui/SystemMessage/SystemMessageRow.d.ts +9 -0
  72. package/dist/esm/types/ui/SystemMessage/index.d.ts +2 -0
  73. package/dist/esm/types/{util → ui}/customize.d.ts +2 -3
  74. package/dist/esm/types/ui/index.d.ts +6 -6
  75. package/dist/esm/types/ui/localizer.d.ts +5 -0
  76. package/dist/esm/types/util/index.d.ts +0 -1
  77. package/dist/index.d.ts +353 -142
  78. package/package.json +92 -90
  79. package/src/ChatifyContext.tsx +41 -41
  80. package/src/core/action.tsx +405 -319
  81. package/src/core/client.ts +143 -137
  82. package/src/core/index.ts +17 -14
  83. package/src/core/models.tsx +82 -75
  84. package/src/core/reducer.tsx +87 -86
  85. package/src/core/state.ts +92 -38
  86. package/src/core/useAddChatMutation.tsx +22 -0
  87. package/src/core/useAddMemberMutation.tsx +25 -0
  88. package/src/core/useFetchNextMutation.tsx +28 -0
  89. package/src/core/useGetAccountsQuery.tsx +33 -0
  90. package/src/core/useGetChatListQuery.tsx +33 -0
  91. package/src/core/useGetChatQuery.tsx +34 -0
  92. package/src/core/useGetMessagesQuery.tsx +35 -0
  93. package/src/core/useReadMonitor.tsx +32 -31
  94. package/src/core/useRemoveMemberMutation.tsx +23 -0
  95. package/src/core/useSendMutation.tsx +24 -0
  96. package/src/core/useSignalRMonitor.tsx +66 -52
  97. package/src/core/useUpdateChatNameMutation.tsx +23 -0
  98. package/src/index.ts +3 -3
  99. package/src/{ui/styles → styles}/aside.scss +94 -94
  100. package/src/styles/chat.scss +222 -0
  101. package/src/styles/index.scss +79 -0
  102. package/src/{ui/styles → styles}/keyframes.scss +14 -14
  103. package/src/{ui/styles → styles}/mixins.scss +20 -20
  104. package/src/styles/settings.scss +5 -0
  105. package/src/{ui/styles → styles}/variables.scss +10 -10
  106. package/src/ui/AddChatButton.tsx +15 -19
  107. package/src/ui/Avatar.tsx +18 -18
  108. package/src/ui/ChatList/ChatList.tsx +42 -0
  109. package/src/ui/ChatList/ChatListItemBox.tsx +22 -0
  110. package/src/ui/ChatList/ChatListItemLastMessage.tsx +13 -0
  111. package/src/ui/ChatList/ChatListItemLastMessageAuthor.tsx +20 -0
  112. package/src/ui/ChatList/ChatListItemLastMessageContent.tsx +21 -0
  113. package/src/ui/ChatList/ChatListItemName.tsx +13 -0
  114. package/src/ui/ChatList/ChatListItemUnreadCount.tsx +12 -0
  115. package/src/ui/ChatList/index.ts +7 -0
  116. package/src/ui/ChatName.tsx +10 -15
  117. package/src/ui/ChatPanel/ChatBody.tsx +44 -0
  118. package/src/ui/ChatPanel/ChatHeader.tsx +33 -0
  119. package/src/ui/{ChatHeaderMembers.tsx → ChatPanel/ChatHeaderMembers.tsx} +26 -30
  120. package/src/ui/ChatPanel/ChatHeaderName.tsx +67 -0
  121. package/src/ui/ChatPanel/ChatMembersButton.tsx +21 -0
  122. package/src/ui/ChatPanel/ChatMembersPanel.tsx +117 -0
  123. package/src/ui/ChatPanel/ChatPanel.tsx +27 -0
  124. package/src/ui/ChatPanel/index.ts +6 -0
  125. package/src/ui/Chatify.tsx +148 -106
  126. package/src/ui/CreateChatPanel/CreateChatForm.tsx +36 -0
  127. package/src/ui/CreateChatPanel/CreateChatMemberInput.tsx +66 -0
  128. package/src/ui/CreateChatPanel/CreateChatNameInput.tsx +25 -0
  129. package/src/ui/CreateChatPanel/CreateChatPanel.tsx +33 -0
  130. package/src/ui/CreateChatPanel/index.ts +4 -0
  131. package/src/ui/Icon.tsx +33 -21
  132. package/src/ui/InputBox/InputBox.tsx +38 -0
  133. package/src/ui/InputBox/InputFilesBox.tsx +9 -0
  134. package/src/ui/InputBox/InputSubmitButtonBox.tsx +17 -0
  135. package/src/ui/InputBox/InputTextBox.tsx +50 -0
  136. package/src/ui/InputBox/index.ts +4 -0
  137. package/src/ui/Layout/Aside.tsx +10 -0
  138. package/src/ui/Layout/Body.tsx +10 -0
  139. package/src/ui/Layout/Footer.tsx +3 -0
  140. package/src/ui/Layout/Header.tsx +10 -0
  141. package/src/ui/Layout/Main.tsx +15 -0
  142. package/src/ui/Layout/index.ts +5 -0
  143. package/src/ui/Message/MessageAuthor.tsx +13 -0
  144. package/src/ui/Message/MessageBox.tsx +20 -0
  145. package/src/ui/Message/MessageContent.tsx +13 -0
  146. package/src/ui/Message/MessageInfoBox.tsx +25 -0
  147. package/src/ui/Message/MessageRow.tsx +24 -0
  148. package/src/ui/Message/MessageText.tsx +7 -0
  149. package/src/ui/Message/index.ts +6 -0
  150. package/src/ui/MessageReadObserver.tsx +45 -0
  151. package/src/ui/MessageSkeleton.tsx +19 -19
  152. package/src/ui/Next.tsx +48 -0
  153. package/src/ui/SendingMessage/SendingMessageBox.tsx +16 -0
  154. package/src/ui/SendingMessage/SendingMessageContent.tsx +13 -0
  155. package/src/ui/SendingMessage/SendingMessageInfoBox.tsx +13 -0
  156. package/src/ui/SendingMessage/SendingMessageText.tsx +7 -0
  157. package/src/ui/SendingMessage/index.ts +4 -0
  158. package/src/ui/SystemMessage/SystemMessageBox.tsx +20 -0
  159. package/src/ui/SystemMessage/SystemMessageRow.tsx +43 -0
  160. package/src/ui/SystemMessage/index.ts +2 -0
  161. package/src/{util → ui}/customize.tsx +45 -45
  162. package/src/ui/index.ts +11 -11
  163. package/src/ui/localizer.tsx +80 -68
  164. package/src/util/index.ts +2 -3
  165. package/src/util/uniqBy.tsx +17 -17
  166. package/src/util/uniqId.tsx +3 -3
  167. package/dist/cjs/index.js +0 -2
  168. package/dist/cjs/index.js.map +0 -1
  169. package/dist/cjs/types/ChatifyContext.d.ts +0 -11
  170. package/dist/cjs/types/core/action.d.ts +0 -76
  171. package/dist/cjs/types/core/client.d.ts +0 -35
  172. package/dist/cjs/types/core/index.d.ts +0 -14
  173. package/dist/cjs/types/core/models.d.ts +0 -64
  174. package/dist/cjs/types/core/reducer.d.ts +0 -11
  175. package/dist/cjs/types/core/state.d.ts +0 -25
  176. package/dist/cjs/types/core/useAccounts.d.ts +0 -1
  177. package/dist/cjs/types/core/useAddChat.d.ts +0 -2
  178. package/dist/cjs/types/core/useAddMember.d.ts +0 -2
  179. package/dist/cjs/types/core/useAddMessage.d.ts +0 -5
  180. package/dist/cjs/types/core/useChatList.d.ts +0 -1
  181. package/dist/cjs/types/core/useLoadMore.d.ts +0 -3
  182. package/dist/cjs/types/core/useMessages.d.ts +0 -15
  183. package/dist/cjs/types/core/useMutation.d.ts +0 -12
  184. package/dist/cjs/types/core/useQuery.d.ts +0 -7
  185. package/dist/cjs/types/core/useReadMonitor.d.ts +0 -1
  186. package/dist/cjs/types/core/useRemoveMember.d.ts +0 -2
  187. package/dist/cjs/types/core/useSignalRMonitor.d.ts +0 -2
  188. package/dist/cjs/types/index.d.ts +0 -3
  189. package/dist/cjs/types/ui/AddChat.d.ts +0 -1
  190. package/dist/cjs/types/ui/AddChatButton.d.ts +0 -2
  191. package/dist/cjs/types/ui/Aside.d.ts +0 -1
  192. package/dist/cjs/types/ui/Avatar.d.ts +0 -6
  193. package/dist/cjs/types/ui/Chat.d.ts +0 -4
  194. package/dist/cjs/types/ui/ChatBody.d.ts +0 -4
  195. package/dist/cjs/types/ui/ChatHeader.d.ts +0 -4
  196. package/dist/cjs/types/ui/ChatHeaderMembers.d.ts +0 -5
  197. package/dist/cjs/types/ui/ChatHeaderSettingsButton.d.ts +0 -5
  198. package/dist/cjs/types/ui/ChatListItem.d.ts +0 -11
  199. package/dist/cjs/types/ui/ChatName.d.ts +0 -5
  200. package/dist/cjs/types/ui/ChatSettings.d.ts +0 -1
  201. package/dist/cjs/types/ui/Chatify.d.ts +0 -49
  202. package/dist/cjs/types/ui/Footer.d.ts +0 -2
  203. package/dist/cjs/types/ui/Header.d.ts +0 -2
  204. package/dist/cjs/types/ui/Icon.d.ts +0 -7
  205. package/dist/cjs/types/ui/InputForm.d.ts +0 -1
  206. package/dist/cjs/types/ui/LoadMore.d.ts +0 -4
  207. package/dist/cjs/types/ui/Main.d.ts +0 -1
  208. package/dist/cjs/types/ui/Message.d.ts +0 -18
  209. package/dist/cjs/types/ui/MessageSkeleton.d.ts +0 -4
  210. package/dist/cjs/types/ui/SendingMessage.d.ts +0 -10
  211. package/dist/cjs/types/ui/SystemMessage.d.ts +0 -8
  212. package/dist/cjs/types/ui/index.d.ts +0 -11
  213. package/dist/cjs/types/ui/localizer.d.ts +0 -32
  214. package/dist/cjs/types/util/customize.d.ts +0 -12
  215. package/dist/cjs/types/util/index.d.ts +0 -3
  216. package/dist/cjs/types/util/uniqBy.d.ts +0 -1
  217. package/dist/cjs/types/util/uniqId.d.ts +0 -1
  218. package/dist/esm/types/core/useAccounts.d.ts +0 -1
  219. package/dist/esm/types/core/useAddChat.d.ts +0 -2
  220. package/dist/esm/types/core/useAddMember.d.ts +0 -2
  221. package/dist/esm/types/core/useAddMessage.d.ts +0 -5
  222. package/dist/esm/types/core/useChat.d.ts +0 -3
  223. package/dist/esm/types/core/useChatList.d.ts +0 -1
  224. package/dist/esm/types/core/useLoadMore.d.ts +0 -3
  225. package/dist/esm/types/core/useMessages.d.ts +0 -15
  226. package/dist/esm/types/core/useMutation.d.ts +0 -12
  227. package/dist/esm/types/core/useQuery.d.ts +0 -7
  228. package/dist/esm/types/core/useRemoveMember.d.ts +0 -2
  229. package/dist/esm/types/ui/AddChat.d.ts +0 -1
  230. package/dist/esm/types/ui/Aside.d.ts +0 -1
  231. package/dist/esm/types/ui/Chat.d.ts +0 -4
  232. package/dist/esm/types/ui/ChatBody.d.ts +0 -4
  233. package/dist/esm/types/ui/ChatHeader.d.ts +0 -4
  234. package/dist/esm/types/ui/ChatHeaderMembers.d.ts +0 -5
  235. package/dist/esm/types/ui/ChatHeaderSettingsButton.d.ts +0 -5
  236. package/dist/esm/types/ui/ChatListItem.d.ts +0 -11
  237. package/dist/esm/types/ui/ChatSettings.d.ts +0 -1
  238. package/dist/esm/types/ui/Footer.d.ts +0 -2
  239. package/dist/esm/types/ui/Header.d.ts +0 -2
  240. package/dist/esm/types/ui/InputForm.d.ts +0 -1
  241. package/dist/esm/types/ui/LoadMore.d.ts +0 -4
  242. package/dist/esm/types/ui/Main.d.ts +0 -1
  243. package/dist/esm/types/ui/Message.d.ts +0 -18
  244. package/dist/esm/types/ui/SendingMessage.d.ts +0 -10
  245. package/dist/esm/types/ui/SystemMessage.d.ts +0 -8
  246. package/src/core/useAccounts.tsx +0 -11
  247. package/src/core/useAddChat.tsx +0 -12
  248. package/src/core/useAddMember.tsx +0 -12
  249. package/src/core/useAddMessage.tsx +0 -40
  250. package/src/core/useChat.tsx +0 -12
  251. package/src/core/useChatList.tsx +0 -10
  252. package/src/core/useLoadMore.tsx +0 -42
  253. package/src/core/useMessages.tsx +0 -23
  254. package/src/core/useMutation.tsx +0 -48
  255. package/src/core/useQuery.tsx +0 -45
  256. package/src/core/useRemoveMember.tsx +0 -12
  257. package/src/ui/AddChat.tsx +0 -55
  258. package/src/ui/Aside.tsx +0 -41
  259. package/src/ui/Chat.tsx +0 -26
  260. package/src/ui/ChatBody.tsx +0 -43
  261. package/src/ui/ChatHeader.tsx +0 -33
  262. package/src/ui/ChatHeaderSettingsButton.tsx +0 -26
  263. package/src/ui/ChatListItem.tsx +0 -101
  264. package/src/ui/ChatSettings.tsx +0 -59
  265. package/src/ui/Footer.tsx +0 -7
  266. package/src/ui/Header.tsx +0 -14
  267. package/src/ui/InputForm.tsx +0 -51
  268. package/src/ui/LoadMore.tsx +0 -40
  269. package/src/ui/Main.tsx +0 -16
  270. package/src/ui/Message.tsx +0 -118
  271. package/src/ui/SendingMessage.tsx +0 -50
  272. package/src/ui/SystemMessage.tsx +0 -32
  273. package/src/ui/styles/index.scss +0 -248
@@ -0,0 +1,5 @@
1
+ export * from './Aside';
2
+ export * from './Header';
3
+ export * from './Footer';
4
+ export * from './Main';
5
+ export * from './Body';
@@ -0,0 +1,13 @@
1
+ import { customize } from '../customize';
2
+ import { Avatar } from '../Avatar';
3
+ import type { MessageBoxProps } from './MessageBox';
4
+
5
+ export const MessageAuthor = customize('MessageAuthor', (props: MessageBoxProps) => {
6
+ const { sentBy } = props.message;
7
+
8
+ return (
9
+ <div className="wxchtf-message-author">
10
+ <Avatar account={sentBy} />
11
+ </div>
12
+ );
13
+ });
@@ -0,0 +1,20 @@
1
+ import { useRef } from 'react';
2
+ import { Message } from '../../core';
3
+ import { customize } from '../customize';
4
+ import { MessageReadObserver } from '../MessageReadObserver';
5
+ import { MessageRow } from './MessageRow';
6
+
7
+ export interface MessageBoxProps {
8
+ message: Message;
9
+ }
10
+
11
+ export const MessageBox = customize('MessageBox', (props: MessageBoxProps) => {
12
+ const ref = useRef<HTMLDivElement | null>(null);
13
+
14
+ return (
15
+ <>
16
+ <MessageReadObserver messageRef={ref} {...props} />
17
+ <MessageRow containerRef={ref} {...props} />
18
+ </>
19
+ );
20
+ });
@@ -0,0 +1,13 @@
1
+ import { customize } from '../customize';
2
+ import { MessageText } from './MessageText';
3
+ import { MessageInfoBox } from './MessageInfoBox';
4
+ import type { MessageBoxProps } from './MessageBox';
5
+
6
+ export const MessageContent = customize('MessageContent', (props: MessageBoxProps) => {
7
+ return (
8
+ <div className="wxchtf-message-content">
9
+ <MessageText {...props} />
10
+ <MessageInfoBox {...props} />
11
+ </div>
12
+ );
13
+ });
@@ -0,0 +1,25 @@
1
+ import { useMe } from '../../ChatifyContext';
2
+ import { useSelect } from '../../core';
3
+ import { customize } from '../customize';
4
+ import { useLocalizer } from '../localizer';
5
+ import type { MessageBoxProps } from './MessageBox';
6
+
7
+ export const MessageInfoBox = customize('MessageInfoBox', (props: MessageBoxProps) => {
8
+ const { message } = props;
9
+ const { id, sentBy, sentAt } = message;
10
+ const me = useMe();
11
+ const my = sentBy.id === me;
12
+ const localizer = useLocalizer();
13
+ const reading = useSelect((x) => x.queue.read.queued.includes(id), []);
14
+
15
+ return (
16
+ <div className="wxchtf-message-info-box">
17
+ <div className="wxchtf-message-sent-at">{localizer.timestamp(sentAt)}</div>
18
+ {!my && (
19
+ <div className="wxchtf-message-read-box">
20
+ {reading ? localizer.message.reading() : localizer.message.read()}
21
+ </div>
22
+ )}
23
+ </div>
24
+ );
25
+ });
@@ -0,0 +1,24 @@
1
+ import { useMe } from '../../ChatifyContext';
2
+ import { Ref } from 'react';
3
+ import { customize } from '../customize';
4
+ import { MessageAuthor } from './MessageAuthor';
5
+ import { MessageContent } from './MessageContent';
6
+ import { MessageBoxProps } from './MessageBox';
7
+
8
+ export interface MessageRowProps extends MessageBoxProps {
9
+ containerRef?: Ref<HTMLDivElement>;
10
+ }
11
+
12
+ export const MessageRow = customize('MessageRow', (props: MessageRowProps) => {
13
+ const { message, containerRef } = props;
14
+ const { sentBy } = message;
15
+ const me = useMe();
16
+ const my = sentBy.id === me;
17
+
18
+ return (
19
+ <div ref={containerRef} className={'wxchtf-message' + (my ? ' --my' : '')}>
20
+ <MessageAuthor {...props} />
21
+ <MessageContent {...props} />
22
+ </div>
23
+ );
24
+ });
@@ -0,0 +1,7 @@
1
+ import { customize } from '../customize';
2
+ import { MessageBoxProps } from './MessageBox';
3
+
4
+ export const MessageText = customize('MessageText', (props: MessageBoxProps) => {
5
+ const { text } = props.message;
6
+ return <div className="wxchtf-message-text">{text}</div>;
7
+ });
@@ -0,0 +1,6 @@
1
+ export * from './MessageAuthor';
2
+ export * from './MessageBox';
3
+ export * from './MessageContent';
4
+ export * from './MessageInfoBox';
5
+ export * from './MessageRow';
6
+ export * from './MessageText';
@@ -0,0 +1,45 @@
1
+ import { FC, RefObject, useEffect, useMemo, useRef } from 'react';
2
+ import { useDispatch, useSelect } from '../core';
3
+ import { customize } from './customize';
4
+ import { MessageBoxProps } from './Message/MessageBox';
5
+
6
+ export interface MessageReadObserverProps extends MessageBoxProps {
7
+ messageRef: RefObject<HTMLDivElement | null>;
8
+ }
9
+
10
+ export const MessageReadObserver = customize<FC<MessageReadObserverProps>>('MessageReadObserver', (props) => {
11
+ const { message, messageRef } = props;
12
+ const dispatch = useDispatch();
13
+ const isRead = useSelect((x) => {
14
+ const lastReadMessageId = x.query.chatList.data!.find((x) => x.id === message.chatId)!.lastReadMessageId;
15
+ return lastReadMessageId != null && message.id.localeCompare(lastReadMessageId) <= 0;
16
+ }, []);
17
+
18
+ const readRef = useRef(isRead);
19
+
20
+ useEffect(() => {
21
+ readRef.current = readRef.current || isRead;
22
+ }, [isRead]);
23
+
24
+ const observer = useMemo(
25
+ () =>
26
+ new IntersectionObserver(([entry]) => {
27
+ if (entry.isIntersecting && !readRef.current) {
28
+ readRef.current = true;
29
+ dispatch({ type: 'read', data: { id: message.id, timestamp: new Date().getTime() } });
30
+ }
31
+ }),
32
+
33
+ // eslint-disable-next-line react-hooks/exhaustive-deps
34
+ [],
35
+ );
36
+
37
+ useEffect(() => {
38
+ observer.observe(messageRef.current!);
39
+ return () => observer.disconnect();
40
+
41
+ // eslint-disable-next-line react-hooks/exhaustive-deps
42
+ }, [observer]);
43
+
44
+ return <></>;
45
+ });
@@ -1,19 +1,19 @@
1
- import { Skeleton } from 'antd';
2
-
3
- export interface MessageSkeletonProps {
4
- count?: number;
5
- }
6
-
7
- export function MessageSkeleton(props: MessageSkeletonProps) {
8
- const { count = 1 } = props;
9
- return (
10
- <>
11
- {Array.from(Array(count)).map((_, index) => (
12
- <div className="wxchtf-message-skeleton" key={index}>
13
- <Skeleton.Avatar className="wxchtf-avatar" active />
14
- <Skeleton.Button active className="wxchtf-content" />
15
- </div>
16
- ))}
17
- </>
18
- );
19
- }
1
+ import { Skeleton } from 'antd';
2
+
3
+ export interface MessageSkeletonProps {
4
+ count?: number;
5
+ }
6
+
7
+ export function MessageSkeleton(props: MessageSkeletonProps) {
8
+ const { count = 1 } = props;
9
+ return (
10
+ <>
11
+ {Array.from(Array(count)).map((_, index) => (
12
+ <div className="wxchtf-message-skeleton" key={index}>
13
+ <Skeleton.Avatar className="wxchtf-avatar" active />
14
+ <Skeleton.Button active className="wxchtf-content" />
15
+ </div>
16
+ ))}
17
+ </>
18
+ );
19
+ }
@@ -0,0 +1,48 @@
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
+ import { useFetchNextMutation } from '../core';
3
+ import { MessageSkeleton } from './MessageSkeleton';
4
+
5
+ export interface NextProps {
6
+ chatId: string;
7
+ }
8
+
9
+ export function Next(props: NextProps) {
10
+ const { chatId } = props;
11
+ const [fetchNext, { isFetching }] = useFetchNextMutation({ chatId });
12
+ const [intersecting, setIntersecting] = useState(false);
13
+ const ref = useRef<HTMLDivElement | null>(null);
14
+ const timerRef = useRef<NodeJS.Timer>();
15
+
16
+ const observer = useMemo(
17
+ () =>
18
+ new IntersectionObserver(([entry]) => {
19
+ if (entry.isIntersecting) {
20
+ timerRef.current = setTimeout(() => setIntersecting(true), 200);
21
+ } else {
22
+ clearTimeout(timerRef.current!);
23
+ }
24
+ }),
25
+ [],
26
+ );
27
+
28
+ useEffect(() => {
29
+ observer.observe(ref.current!);
30
+ return () => observer.disconnect();
31
+ }, [observer]);
32
+
33
+ useEffect(() => {
34
+ if (!intersecting) {
35
+ return;
36
+ }
37
+
38
+ fetchNext();
39
+
40
+ // eslint-disable-next-line react-hooks/exhaustive-deps
41
+ }, [intersecting]);
42
+
43
+ if (isFetching || intersecting) {
44
+ return <MessageSkeleton count={4} />;
45
+ }
46
+
47
+ return <div className="wxchtf-next" ref={ref}></div>;
48
+ }
@@ -0,0 +1,16 @@
1
+ import { File } from '../../core';
2
+ import { customize } from '../customize';
3
+ import { SendingMessageContent } from './SendingMessageContent';
4
+
5
+ export interface SendingMessageBoxProps {
6
+ text: string;
7
+ files: File[];
8
+ }
9
+
10
+ export const SendingMessageBox = customize('SendingMessageBox', (props: SendingMessageBoxProps) => {
11
+ return (
12
+ <div className="wxchtf-sending-message">
13
+ <SendingMessageContent {...props} />
14
+ </div>
15
+ );
16
+ });
@@ -0,0 +1,13 @@
1
+ import { customize } from '../customize';
2
+ import { SendingMessageText } from './SendingMessageText';
3
+ import { SendingMessageInfoBox } from './SendingMessageInfoBox';
4
+ import type { SendingMessageBoxProps } from './SendingMessageBox';
5
+
6
+ export const SendingMessageContent = customize('SendingMessageContent', (props: SendingMessageBoxProps) => {
7
+ return (
8
+ <div className="wxchtf-sending-message-content">
9
+ <SendingMessageText {...props} />
10
+ <SendingMessageInfoBox {...props} />
11
+ </div>
12
+ );
13
+ });
@@ -0,0 +1,13 @@
1
+ import { customize } from '../customize';
2
+ import { useLocalizer } from '../localizer';
3
+ import type { SendingMessageBoxProps } from './SendingMessageBox';
4
+
5
+ export const SendingMessageInfoBox = customize('SendingMessageInfoBox', (_: SendingMessageBoxProps) => {
6
+ const localizer = useLocalizer();
7
+
8
+ return (
9
+ <div className="wxchtf-sending-message-info-box">
10
+ <div className="wxchtf-sending-message-sending-box">{localizer.message.sending()}</div>
11
+ </div>
12
+ );
13
+ });
@@ -0,0 +1,7 @@
1
+ import { customize } from '../customize';
2
+ import type { SendingMessageBoxProps } from './SendingMessageBox';
3
+
4
+ export const SendingMessageText = customize('SendingMessageText', (props: SendingMessageBoxProps) => {
5
+ const { text } = props;
6
+ return <div className="wxchtf-sending-message-text">{text}</div>;
7
+ });
@@ -0,0 +1,4 @@
1
+ export * from './SendingMessageBox';
2
+ export * from './SendingMessageContent';
3
+ export * from './SendingMessageInfoBox';
4
+ export * from './SendingMessageText';
@@ -0,0 +1,20 @@
1
+ import { useRef } from 'react';
2
+ import { customize } from '../customize';
3
+ import { Message } from '../../core';
4
+ import { MessageReadObserver } from '../MessageReadObserver';
5
+ import { SystemMessageRow } from './SystemMessageRow';
6
+
7
+ export interface SystemMessageBoxProps {
8
+ message: Message;
9
+ }
10
+
11
+ export const SystemMessageBox = customize('SystemMessageBox', (props: SystemMessageBoxProps) => {
12
+ const ref = useRef<HTMLDivElement | null>(null);
13
+
14
+ return (
15
+ <>
16
+ <MessageReadObserver messageRef={ref} {...props} />
17
+ <SystemMessageRow containerRef={ref} {...props} />
18
+ </>
19
+ );
20
+ });
@@ -0,0 +1,43 @@
1
+ import { Ref } from 'react';
2
+ import { customize } from '../customize';
3
+ import { Localizer, useLocalizer } from '../localizer';
4
+ import { Message } from '../../core';
5
+
6
+ export interface SystemMessageRowProps {
7
+ message: Message;
8
+ containerRef?: Ref<HTMLDivElement>;
9
+ }
10
+
11
+ export function formatSystemMessage(localizer: Localizer, text: string): React.ReactNode {
12
+ if (text === 'chatify://chat-created') {
13
+ return localizer.system.chatCreated();
14
+ }
15
+
16
+ if (text.startsWith('chatify://member-added')) {
17
+ return localizer.system.memberAdded();
18
+ }
19
+
20
+ if (text.startsWith('chatify://member-removed')) {
21
+ return localizer.system.memberRemoved();
22
+ }
23
+
24
+ if (text.startsWith('chatify://chat-name-changed::')) {
25
+ const data = JSON.parse(text.substring('chatify://chat-name-changed::'.length));
26
+ return localizer.system.chatNameChanged(data.newName);
27
+ }
28
+
29
+ return text;
30
+ }
31
+
32
+ export const SystemMessageRow = customize('SystemMessageRow', (props: SystemMessageRowProps) => {
33
+ const { message, containerRef } = props;
34
+ const { text, sentAt } = message;
35
+ const localizer = useLocalizer();
36
+
37
+ return (
38
+ <div ref={containerRef} className="wxchtf-system-message">
39
+ <div className="wxchtf-text">{formatSystemMessage(localizer, text)}</div>
40
+ <div className="wxchtf-timestamp">{localizer.timestamp(sentAt)}</div>
41
+ </div>
42
+ );
43
+ });
@@ -0,0 +1,2 @@
1
+ export * from './SystemMessageBox';
2
+ export * from './SystemMessageRow';
@@ -1,45 +1,45 @@
1
- import React, { FC, PropsWithChildren, useContext } from 'react';
2
-
3
- export type Customizable<TComponent extends React.ComponentType<any>, TKey extends string> = TComponent & {
4
- Component: TComponent;
5
- key: TKey;
6
- };
7
-
8
- const CustomizeContext = React.createContext<CustomizeProviderValue>(null!);
9
-
10
- export interface CustomizeProviderValue {
11
- [key: string]: React.ComponentType<any> | null;
12
- }
13
-
14
- export function CustomizeProvider(props: PropsWithChildren<{ value: CustomizeProviderValue }>) {
15
- const { children, value } = props;
16
- return <CustomizeContext.Provider value={value}>{children}</CustomizeContext.Provider>;
17
- }
18
-
19
- function useCustom<TComponent extends React.ComponentType>(key: string): TComponent | undefined | null {
20
- const value = useContext(CustomizeContext);
21
- return value[key] as TComponent | null | undefined;
22
- }
23
-
24
- export function customize<TComponent extends React.ComponentType<any>, TKey extends string>(
25
- key: TKey,
26
- Component: TComponent,
27
- ): Customizable<TComponent, TKey> {
28
- const Result: FC<any> = React.forwardRef<TComponent, any>((props: any, forwardRef) => {
29
- const Custom = useCustom(key);
30
-
31
- if (Custom === null) {
32
- return null;
33
- }
34
-
35
- if (Custom) {
36
- return <Custom {...props} ref={forwardRef} />;
37
- }
38
-
39
- return <Component {...props} ref={forwardRef} />;
40
- });
41
-
42
- Result.displayName = 'Customizable.' + Component.displayName;
43
-
44
- return Object.assign(Result, { key, Component }) as any;
45
- }
1
+ import React, { FC, PropsWithChildren, useContext } from 'react';
2
+
3
+ export type Customizable<TComponent extends React.ComponentType<any>> = TComponent & {
4
+ Component: TComponent;
5
+ };
6
+
7
+ const CustomizeContext = React.createContext<CustomizeProviderValue>(null!);
8
+
9
+ export interface CustomizeProviderValue {
10
+ [key: string]: React.ComponentType<any> | null;
11
+ }
12
+
13
+ export function CustomizeProvider(props: PropsWithChildren<{ value: CustomizeProviderValue }>) {
14
+ const { children, value } = props;
15
+ return <CustomizeContext.Provider value={value}>{children}</CustomizeContext.Provider>;
16
+ }
17
+
18
+ function useCustom<TComponent extends React.ComponentType>(key: string): TComponent | undefined | null {
19
+ const value = useContext(CustomizeContext);
20
+ return value[key] as TComponent | null | undefined;
21
+ }
22
+
23
+ export function customize<TComponent extends React.ComponentType<any>>(
24
+ key: string,
25
+ Component: TComponent,
26
+ ): TComponent extends React.ComponentType<infer X> ? Customizable<React.ComponentType<X>> : never {
27
+ const Result: FC<any> = React.forwardRef<TComponent, any>((props: any, forwardRef) => {
28
+ const Custom = useCustom(key);
29
+
30
+ if (Custom === null) {
31
+ return null;
32
+ }
33
+
34
+ if (Custom) {
35
+ return <Custom {...props} ref={forwardRef} />;
36
+ }
37
+
38
+ return <Component {...props} ref={forwardRef} />;
39
+ });
40
+
41
+ Component.displayName = Component.displayName || key;
42
+ Result.displayName = 'Customizable.' + Component.displayName;
43
+
44
+ return Object.assign(Result, { key, Component }) as any;
45
+ }
package/src/ui/index.ts CHANGED
@@ -1,11 +1,11 @@
1
- export * from './Chatify';
2
- export * from './Avatar';
3
- export * from './localizer';
4
- export * from './AddChatButton';
5
- export * from './Header';
6
- export * from './ChatHeader';
7
- export * from './ChatHeaderMembers';
8
- export * from './ChatListItem';
9
- export * from './Message';
10
- export * from './SystemMessage';
11
- export * from './Icon';
1
+ export * from './Chatify';
2
+ export * from './Avatar';
3
+ export * from './localizer';
4
+ export * from './AddChatButton';
5
+ export * from './Layout/Header';
6
+ export * from './ChatPanel/ChatHeader';
7
+ export * from './ChatPanel/ChatHeaderMembers';
8
+ export * from './ChatList/ChatListItemBox';
9
+ export * from './Message/MessageBox';
10
+ export * from './SystemMessage/SystemMessageBox';
11
+ export * from './Icon';
@@ -1,68 +1,80 @@
1
- import dayjs from 'dayjs';
2
- import React, { useContext } from 'react';
3
-
4
- export interface Localizer {
5
- timestamp: (value: string) => string;
6
- system: {
7
- chatCreated: () => string;
8
- memberAdded: () => string;
9
- };
10
- message: {
11
- read: () => React.ReactNode;
12
- reading: () => React.ReactNode;
13
- sending: () => React.ReactNode;
14
- };
15
- addChat: {
16
- title: () => React.ReactNode;
17
- name: {
18
- label: () => React.ReactNode;
19
- required: () => string;
20
- max250: () => string;
21
- };
22
- members: {
23
- label: () => React.ReactNode;
24
- required: () => string;
25
- };
26
- submitBtn: () => React.ReactNode;
27
- };
28
-
29
- input: {
30
- placeholder: () => string;
31
- };
32
- }
33
-
34
- export const LocalizerContext = React.createContext<Localizer>(null!);
35
-
36
- export function useLocalizer() {
37
- return useContext(LocalizerContext);
38
- }
39
-
40
- export const defaultLocalizer: Localizer = {
41
- timestamp: (value: string) => dayjs(value).format('HH:mm'),
42
- message: {
43
- read: () => 'Read',
44
- reading: () => 'Reading...',
45
- sending: () => 'Sending...',
46
- },
47
- addChat: {
48
- title: () => 'Add chat',
49
- name: {
50
- label: () => 'Name',
51
- required: () => `Name is required`,
52
- max250: () => 'Max 250 characters allowed',
53
- },
54
- members: {
55
- label: () => 'Members',
56
- required: () => 'Members is required',
57
- },
58
- submitBtn: () => 'Submit',
59
- },
60
- system: {
61
- chatCreated: () => 'Chat created',
62
- memberAdded: () => 'New member added',
63
- },
64
-
65
- input: {
66
- placeholder: () => 'Start typing (Ctrl/⌘Cmd + Enter to send) ...',
67
- },
68
- };
1
+ import dayjs from 'dayjs';
2
+ import React, { useContext } from 'react';
3
+
4
+ export interface Localizer {
5
+ timestamp: (value: string) => string;
6
+ system: {
7
+ chatCreated: () => string;
8
+ memberAdded: () => string;
9
+ memberRemoved: () => string;
10
+ chatNameChanged: (newName: string) => string;
11
+ };
12
+ message: {
13
+ read: () => React.ReactNode;
14
+ reading: () => React.ReactNode;
15
+ sending: () => React.ReactNode;
16
+ };
17
+ addChat: {
18
+ title: () => React.ReactNode;
19
+ name: {
20
+ label: () => React.ReactNode;
21
+ required: () => string;
22
+ max250: () => string;
23
+ };
24
+ members: {
25
+ label: () => React.ReactNode;
26
+ required: () => string;
27
+ };
28
+ submitBtn: () => React.ReactNode;
29
+ };
30
+
31
+ input: {
32
+ placeholder: () => string;
33
+ };
34
+
35
+ settings: {
36
+ members: () => string;
37
+ };
38
+ }
39
+
40
+ export const LocalizerContext = React.createContext<Localizer>(null!);
41
+
42
+ export function useLocalizer() {
43
+ return useContext(LocalizerContext);
44
+ }
45
+
46
+ export const defaultLocalizer: Localizer = {
47
+ timestamp: (value: string) => dayjs(value).format('HH:mm'),
48
+ message: {
49
+ read: () => 'Read',
50
+ reading: () => 'Reading...',
51
+ sending: () => 'Sending...',
52
+ },
53
+ addChat: {
54
+ title: () => 'Add chat',
55
+ name: {
56
+ label: () => 'Name',
57
+ required: () => `Name is required`,
58
+ max250: () => 'Max 250 characters allowed',
59
+ },
60
+ members: {
61
+ label: () => 'Members',
62
+ required: () => 'Members is required',
63
+ },
64
+ submitBtn: () => 'Submit',
65
+ },
66
+ system: {
67
+ chatCreated: () => 'Chat created',
68
+ memberAdded: () => 'New member added',
69
+ memberRemoved: () => 'Member removed',
70
+ chatNameChanged: (newName: string) => `Chat name changed to '${newName}'`,
71
+ },
72
+
73
+ input: {
74
+ placeholder: () => 'Start typing (Ctrl/⌘Cmd + Enter to send) ...',
75
+ },
76
+
77
+ settings: {
78
+ members: () => 'Members',
79
+ },
80
+ };