@ethora/chat-component-rn 26.7.2 → 26.7.4

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 (263) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +9 -8
  3. package/lib/commonjs/assets/icons.js +7 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/Header/HeaderRoomList.js +20 -6
  6. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/ChatRoom.js +86 -7
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/ChatWrapper.js +18 -0
  10. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/MessageList.js +11 -4
  12. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +5 -5
  14. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  15. package/lib/commonjs/components/MainComponents/RoomList.js +62 -32
  16. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  17. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +208 -70
  18. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  19. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +307 -99
  20. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  21. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +544 -200
  22. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  23. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
  24. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  25. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
  26. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  27. package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
  28. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  29. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -104
  30. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  31. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +556 -0
  32. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  33. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
  34. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  35. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  36. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  37. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
  38. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  39. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
  40. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  41. package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
  42. package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
  43. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +17 -7
  44. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  45. package/lib/commonjs/components/styled/SendInput.js +80 -1
  46. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  47. package/lib/commonjs/components/styled/StyledComponents.js +9 -3
  48. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  49. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  50. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  51. package/lib/commonjs/context/xmppProvider.js +12 -0
  52. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  53. package/lib/commonjs/helpers/getChatBackground.js +23 -0
  54. package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
  55. package/lib/commonjs/helpers/historyPreloadScheduler.js +65 -2
  56. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  57. package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
  58. package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
  59. package/lib/commonjs/helpers/shallowEqual.js +36 -0
  60. package/lib/commonjs/helpers/shallowEqual.js.map +1 -0
  61. package/lib/commonjs/helpers/sheetGestures.js +32 -0
  62. package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
  63. package/lib/commonjs/hooks/useChatWrapperInit.js +15 -0
  64. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  65. package/lib/commonjs/hooks/useComposing.js +27 -0
  66. package/lib/commonjs/hooks/useComposing.js.map +1 -1
  67. package/lib/commonjs/hooks/useSendMessage.js +27 -1
  68. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  69. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +6 -1
  70. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  71. package/lib/commonjs/i18n/strings.js +121 -1
  72. package/lib/commonjs/i18n/strings.js.map +1 -1
  73. package/lib/commonjs/networking/api-requests/user.api.js +59 -0
  74. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  75. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +6 -2
  76. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  77. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  78. package/lib/commonjs/roomStore/chatSettingsSlice.js +3 -1
  79. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  80. package/lib/commonjs/roomStore/roomsSlice.js +2 -2
  81. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  82. package/lib/module/assets/icons.js +6 -1
  83. package/lib/module/assets/icons.js.map +1 -1
  84. package/lib/module/components/Header/HeaderRoomList.js +20 -6
  85. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  86. package/lib/module/components/MainComponents/ChatRoom.js +87 -8
  87. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  88. package/lib/module/components/MainComponents/ChatWrapper.js +19 -1
  89. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  90. package/lib/module/components/MainComponents/MessageList.js +11 -4
  91. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  92. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +5 -5
  93. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  94. package/lib/module/components/MainComponents/RoomList.js +62 -32
  95. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  96. package/lib/module/components/Menu/HeaderRoomListMenu.js +211 -73
  97. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  98. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +298 -102
  99. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  100. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +547 -204
  101. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  102. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
  103. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  104. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
  105. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  106. package/lib/module/components/Modals/Modal/Modal.js +9 -1
  107. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  108. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -106
  109. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  110. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +548 -0
  111. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  112. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
  113. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  114. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  115. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  116. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
  117. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  118. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
  119. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  120. package/lib/module/components/Modals/styledModalComponents.js +9 -2
  121. package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
  122. package/lib/module/components/RoomComponents/ChatRoomItem.js +17 -7
  123. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  124. package/lib/module/components/styled/SendInput.js +80 -1
  125. package/lib/module/components/styled/SendInput.js.map +1 -1
  126. package/lib/module/components/styled/StyledComponents.js +9 -3
  127. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  128. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  129. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  130. package/lib/module/context/xmppProvider.js +12 -0
  131. package/lib/module/context/xmppProvider.js.map +1 -1
  132. package/lib/module/helpers/getChatBackground.js +18 -0
  133. package/lib/module/helpers/getChatBackground.js.map +1 -0
  134. package/lib/module/helpers/historyPreloadScheduler.js +66 -3
  135. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  136. package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
  137. package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
  138. package/lib/module/helpers/shallowEqual.js +31 -0
  139. package/lib/module/helpers/shallowEqual.js.map +1 -0
  140. package/lib/module/helpers/sheetGestures.js +26 -0
  141. package/lib/module/helpers/sheetGestures.js.map +1 -0
  142. package/lib/module/hooks/useChatWrapperInit.js +15 -0
  143. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  144. package/lib/module/hooks/useComposing.js +28 -1
  145. package/lib/module/hooks/useComposing.js.map +1 -1
  146. package/lib/module/hooks/useSendMessage.js +28 -2
  147. package/lib/module/hooks/useSendMessage.js.map +1 -1
  148. package/lib/module/hooks/useUnreadMessagesCounter.js +6 -1
  149. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  150. package/lib/module/i18n/strings.js +121 -1
  151. package/lib/module/i18n/strings.js.map +1 -1
  152. package/lib/module/networking/api-requests/user.api.js +56 -0
  153. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  154. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +6 -2
  155. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  156. package/lib/module/networking/xmppClient.js.map +1 -1
  157. package/lib/module/roomStore/chatSettingsSlice.js +3 -1
  158. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  159. package/lib/module/roomStore/roomsSlice.js +1 -1
  160. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  161. package/lib/typescript/assets/icons.d.ts +12 -0
  162. package/lib/typescript/assets/icons.d.ts.map +1 -1
  163. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  164. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  165. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  166. package/lib/typescript/components/MainComponents/MessageList.d.ts +10 -1
  167. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  168. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  169. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  170. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
  171. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  172. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
  173. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  174. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
  175. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
  176. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  177. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  178. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
  179. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
  180. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
  181. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
  182. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
  183. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
  184. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
  185. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
  186. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
  187. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  188. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
  189. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  190. package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
  191. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  192. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  193. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  194. package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
  195. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  196. package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
  197. package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
  198. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  199. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
  200. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
  201. package/lib/typescript/helpers/shallowEqual.d.ts +11 -0
  202. package/lib/typescript/helpers/shallowEqual.d.ts.map +1 -0
  203. package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
  204. package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
  205. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  206. package/lib/typescript/hooks/useComposing.d.ts.map +1 -1
  207. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  208. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
  209. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
  210. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  211. package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
  212. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  213. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +1 -0
  214. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
  215. package/lib/typescript/networking/xmppClient.d.ts +1 -0
  216. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  217. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  218. package/lib/typescript/roomStore/roomsSlice.d.ts +1 -0
  219. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  220. package/lib/typescript/types/types.d.ts +9 -5
  221. package/lib/typescript/types/types.d.ts.map +1 -1
  222. package/package.json +6 -1
  223. package/src/assets/icons.tsx +29 -9
  224. package/src/components/Header/HeaderRoomList.tsx +20 -5
  225. package/src/components/MainComponents/ChatRoom.tsx +92 -8
  226. package/src/components/MainComponents/ChatWrapper.tsx +19 -1
  227. package/src/components/MainComponents/MessageList.tsx +21 -3
  228. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +5 -5
  229. package/src/components/MainComponents/RoomList.tsx +65 -34
  230. package/src/components/Menu/HeaderRoomListMenu.tsx +209 -64
  231. package/src/components/Modals/AttachSheet/AttachSheet.tsx +318 -86
  232. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +599 -278
  233. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
  234. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +4 -2
  235. package/src/components/Modals/Modal/Modal.tsx +7 -0
  236. package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -117
  237. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +615 -0
  238. package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
  239. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
  240. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
  241. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
  242. package/src/components/Modals/styledModalComponents.tsx +9 -2
  243. package/src/components/RoomComponents/ChatRoomItem.tsx +14 -7
  244. package/src/components/styled/SendInput.tsx +83 -2
  245. package/src/components/styled/StyledComponents.ts +9 -3
  246. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
  247. package/src/context/xmppProvider.tsx +14 -0
  248. package/src/helpers/getChatBackground.ts +18 -0
  249. package/src/helpers/historyPreloadScheduler.ts +80 -3
  250. package/src/helpers/mediaLibraryRuntime.ts +25 -0
  251. package/src/helpers/shallowEqual.ts +33 -0
  252. package/src/helpers/sheetGestures.ts +25 -0
  253. package/src/hooks/useChatWrapperInit.ts +15 -0
  254. package/src/hooks/useComposing.tsx +37 -1
  255. package/src/hooks/useSendMessage.tsx +32 -2
  256. package/src/hooks/useUnreadMessagesCounter.ts +11 -0
  257. package/src/i18n/strings.ts +121 -1
  258. package/src/networking/api-requests/user.api.ts +71 -0
  259. package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +17 -3
  260. package/src/networking/xmppClient.ts +5 -1
  261. package/src/roomStore/chatSettingsSlice.ts +3 -1
  262. package/src/roomStore/roomsSlice.ts +1 -1
  263. package/src/types/types.ts +16 -5
@@ -1,4 +1,4 @@
1
- import React, { FC, useMemo } from 'react';
1
+ import React, { FC, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import {
3
3
  Alert,
4
4
  Animated,
@@ -7,6 +7,8 @@ import {
7
7
  TouchableWithoutFeedback,
8
8
  StyleSheet,
9
9
  Dimensions,
10
+ Modal,
11
+ PanResponder,
10
12
  View,
11
13
  } from 'react-native';
12
14
  import {
@@ -16,10 +18,15 @@ import {
16
18
  SettingIcon,
17
19
  } from '../../assets/icons';
18
20
  import { useDispatch } from 'react-redux';
21
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
19
22
  import { setActiveModal } from '../../roomStore/chatSettingsSlice';
20
23
  import { MODAL_TYPES } from '../../helpers/constants/MODAL_TYPES';
21
24
  import { useChatSettingState } from '../../hooks/useChatSettingState';
22
25
  import { useLogout } from '../../hooks/useLogout';
26
+ import {
27
+ shouldClaimVerticalDrag,
28
+ shouldDismissOnDrag,
29
+ } from '../../helpers/sheetGestures';
23
30
  import type { IConfig } from '../../types/types';
24
31
 
25
32
  type LogoutConfig = NonNullable<IConfig['logout']>;
@@ -85,7 +92,7 @@ export const runLogoutFlow = async (
85
92
  }
86
93
  };
87
94
 
88
- const { width } = Dimensions.get('window');
95
+ const { height: windowHeight } = Dimensions.get('window');
89
96
 
90
97
  interface HeaderRoomListMenuProps {
91
98
  isDrawerOpen: boolean;
@@ -106,11 +113,102 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
106
113
  const logoutConfig = config?.logout?.enabled ? config.logout : undefined;
107
114
  const primaryColor = config?.colors?.primary ?? '#0052CD';
108
115
 
109
- const drawerTranslateX = drawerAnimation.interpolate({
116
+ const insets = useSafeAreaInsets();
117
+ // Measured, so the sheet is exactly as tall as its rows and starts
118
+ // fully off-screen no matter how many options the host enables.
119
+ const [sheetHeight, setSheetHeight] = useState(windowHeight * 0.4);
120
+ // Finger offset, layered on top of the open/close animation the parent
121
+ // drives. Reset once the sheet is unmounted, so a swipe-dismissed sheet
122
+ // never snaps back into view on its way out.
123
+ const dragY = useRef(new Animated.Value(0)).current;
124
+ const sheetHeightRef = useRef(sheetHeight);
125
+ sheetHeightRef.current = sheetHeight;
126
+
127
+ // closeDrawer is a fresh function each render; the responder is built
128
+ // once, so it reads the current one through a ref rather than the one it
129
+ // closed over on mount.
130
+ const closeDrawerRef = useRef(closeDrawer);
131
+ closeDrawerRef.current = closeDrawer;
132
+
133
+ useEffect(() => {
134
+ if (!isDrawerOpen) {
135
+ dragY.setValue(0);
136
+ return;
137
+ }
138
+ // Hand `dragY` to the native driver up front. The open/close value is
139
+ // already native (the parent animates it that way), and a transform
140
+ // that mixes a native node with a JS-only one drops the JS updates on
141
+ // the floor — which is exactly a drag that moves nothing.
142
+ Animated.timing(dragY, {
143
+ toValue: 0,
144
+ duration: 0,
145
+ useNativeDriver: true,
146
+ }).start();
147
+ }, [isDrawerOpen, dragY]);
148
+
149
+ const openTranslateY = drawerAnimation.interpolate({
110
150
  inputRange: [0, 1],
111
- outputRange: [width, 0],
151
+ outputRange: [sheetHeight, 0],
112
152
  });
113
153
 
154
+ const dismissByDrag = () => {
155
+ Animated.timing(dragY, {
156
+ toValue: sheetHeightRef.current,
157
+ duration: 180,
158
+ useNativeDriver: true,
159
+ }).start();
160
+ closeDrawerRef.current();
161
+ };
162
+
163
+ const makeDragResponder = (claimOnStart: boolean) =>
164
+ PanResponder.create({
165
+ // The grab area claims on touch-DOWN: nothing to negotiate against,
166
+ // so a pull on the handle always drags.
167
+ onStartShouldSetPanResponder: () => claimOnStart,
168
+ // CAPTURE matters on the body: a drag that starts on a row makes
169
+ // that row's Touchable the responder on touch-down, and a plain
170
+ // `onMoveShouldSetPanResponder` is never consulted afterwards.
171
+ // Capturing on the first clearly-vertical movement takes the gesture
172
+ // back, while a tap (dy ≈ 0) still reaches the row.
173
+ onMoveShouldSetPanResponderCapture: (_evt, g) =>
174
+ claimOnStart || shouldClaimVerticalDrag(g.dy, g.dx),
175
+ onMoveShouldSetPanResponder: (_evt, g) =>
176
+ claimOnStart || shouldClaimVerticalDrag(g.dy, g.dx),
177
+ onPanResponderTerminationRequest: () => false,
178
+ onPanResponderMove: (_evt, g) => {
179
+ dragY.setValue(Math.max(0, g.dy));
180
+ },
181
+ onPanResponderRelease: (_evt, g) => {
182
+ if (shouldDismissOnDrag(g.dy, g.vy)) {
183
+ dismissByDrag();
184
+ return;
185
+ }
186
+ Animated.spring(dragY, {
187
+ toValue: 0,
188
+ tension: 90,
189
+ friction: 14,
190
+ useNativeDriver: true,
191
+ }).start();
192
+ },
193
+ onPanResponderTerminate: () => {
194
+ Animated.spring(dragY, {
195
+ toValue: 0,
196
+ tension: 90,
197
+ friction: 14,
198
+ useNativeDriver: true,
199
+ }).start();
200
+ },
201
+ });
202
+
203
+ // Built once — `useRef(expr)` would re-run PanResponder.create every
204
+ // render and throw the result away.
205
+ const bodyPanRef = useRef<ReturnType<typeof makeDragResponder> | null>(null);
206
+ const handlePanRef = useRef<ReturnType<typeof makeDragResponder> | null>(null);
207
+ if (!bodyPanRef.current) {bodyPanRef.current = makeDragResponder(false);}
208
+ if (!handlePanRef.current) {handlePanRef.current = makeDragResponder(true);}
209
+ const pan = bodyPanRef.current;
210
+ const handlePan = handlePanRef.current;
211
+
114
212
  const menuOptions = useMemo(() => {
115
213
  const options: {
116
214
  label: string;
@@ -122,7 +220,7 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
122
220
  }[] = [
123
221
  {
124
222
  label: 'New Chat',
125
- icon: <AddNewIcon color="#8C8C8C" />,
223
+ icon: <AddNewIcon color={primaryColor} />,
126
224
  onClick: () => {
127
225
  dispatch(setActiveModal(MODAL_TYPES.NEW_CHAT));
128
226
  console.log('New chat clicked');
@@ -131,7 +229,7 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
131
229
  },
132
230
  {
133
231
  label: 'Profile',
134
- icon: <ProfileIcon color="#8C8C8C" />,
232
+ icon: <ProfileIcon color={primaryColor} />,
135
233
  onClick: () => {
136
234
  dispatch(setActiveModal(MODAL_TYPES.PROFILE));
137
235
  console.log('Profile clicked');
@@ -139,7 +237,7 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
139
237
  },
140
238
  {
141
239
  label: 'Settings',
142
- icon: <SettingIcon color="#8C8C8C" />,
240
+ icon: <SettingIcon color={primaryColor} />,
143
241
  onClick: () => {
144
242
  dispatch(setActiveModal(MODAL_TYPES.SETTINGS));
145
243
  console.log('Settings clicked');
@@ -162,47 +260,80 @@ export const HeaderRoomListMenu: FC<HeaderRoomListMenuProps> = ({
162
260
  }, [dispatch, logoutConfig, performLogout, primaryColor, closeDrawer]);
163
261
 
164
262
  return (
165
- <>
263
+ // Presented through a real <Modal>: as an in-tree overlay the sheet was
264
+ // bounded by the room list's own container, so it stopped short of the
265
+ // screen's bottom edge (that pale strip under it) and the dim never
266
+ // reached the host's chrome.
267
+ <Modal
268
+ transparent
269
+ visible={isDrawerOpen}
270
+ animationType="none"
271
+ statusBarTranslucent
272
+ onRequestClose={closeDrawer}
273
+ >
274
+ <TouchableWithoutFeedback onPress={closeDrawer}>
275
+ <Animated.View
276
+ style={[styles.overlay, { opacity: overlayAnimation }]}
277
+ />
278
+ </TouchableWithoutFeedback>
279
+ {/* A bottom sheet rather than the old full-height right-hand drawer:
280
+ * three rows never needed the whole screen, and coming up from the
281
+ * bottom keeps them within thumb reach. Inset by 2pt all round so a
282
+ * sliver of the dimmed screen shows around it. */}
166
283
  <Animated.View
284
+ testID="header-menu-sheet"
285
+ onLayout={(e) => {
286
+ const measured = e.nativeEvent.layout.height;
287
+ if (measured > 0) {setSheetHeight(measured);}
288
+ }}
167
289
  style={[
168
- styles.drawer,
169
- { transform: [{ translateX: drawerTranslateX }] },
290
+ styles.sheet,
291
+ {
292
+ paddingBottom: insets.bottom + 20,
293
+ // Two entries rather than Animated.add: the parent's value is
294
+ // driven natively, and stacking the transforms keeps each node
295
+ // on its own driver instead of mixing them in one expression.
296
+ transform: [{ translateY: openTranslateY }, { translateY: dragY }],
297
+ },
170
298
  ]}
299
+ {...pan.panHandlers}
171
300
  >
172
- {menuOptions.map((option, index) => (
173
- <View key={index} style={styles.menuItemWrapper}>
174
- <TouchableOpacity
175
- style={styles.menuItem}
176
- testID={`header-menu-${option.label}`}
177
- onPress={() => {
178
- option.onClick();
179
- if (!option.closesDrawer) {
180
- closeDrawer();
181
- }
182
- }}
183
- >
184
- <View
185
- style={{
186
- width: 22,
187
- alignItems: 'center',
301
+ {/* Full-width grab area, not just the 40pt pill: it claims the
302
+ * gesture the moment it is touched. */}
303
+ <View
304
+ testID="header-menu-grabber"
305
+ style={styles.grabArea}
306
+ {...handlePan.panHandlers}
307
+ >
308
+ <View style={styles.grabber} />
309
+ </View>
310
+ <View style={styles.card}>
311
+ {menuOptions.map((option, index) => (
312
+ <View key={index} style={styles.menuItemWrapper}>
313
+ <TouchableOpacity
314
+ style={styles.menuItem}
315
+ testID={`header-menu-${option.label}`}
316
+ activeOpacity={0.6}
317
+ onPress={() => {
318
+ option.onClick();
319
+ if (!option.closesDrawer) {
320
+ closeDrawer();
321
+ }
188
322
  }}
189
323
  >
190
- {option.icon}
191
- </View>
192
- <Text style={[styles.label, option?.styles]}>{option.label}</Text>
193
- </TouchableOpacity>
194
- {index < menuOptions.length - 1 && <View style={styles.divider} />}
195
- </View>
196
- ))}
324
+ <View style={styles.iconSlot}>{option.icon}</View>
325
+ <Text style={[styles.label, option?.styles]}>
326
+ {option.label}
327
+ </Text>
328
+ </TouchableOpacity>
329
+ {index < menuOptions.length - 1 && (
330
+ <View style={styles.divider} />
331
+ )}
332
+ </View>
333
+ ))}
334
+ </View>
197
335
  </Animated.View>
198
- {isDrawerOpen && (
199
- <TouchableWithoutFeedback onPress={closeDrawer}>
200
- <Animated.View
201
- style={[styles.overlay, { opacity: overlayAnimation }]}
202
- />
203
- </TouchableWithoutFeedback>
204
- )}
205
- </>
336
+ </Modal>
206
337
  );
207
338
  };
208
339
 
@@ -214,40 +345,54 @@ const styles = StyleSheet.create({
214
345
  menuItem: {
215
346
  flexDirection: 'row',
216
347
  alignItems: 'center',
217
- padding: 16,
348
+ paddingVertical: 18,
349
+ paddingHorizontal: 16,
350
+ },
351
+ iconSlot: {
352
+ width: 26,
353
+ alignItems: 'center',
218
354
  },
219
355
  label: {
220
356
  fontSize: 16,
221
- marginLeft: 10,
357
+ fontWeight: '500',
358
+ color: '#141414',
359
+ marginLeft: 12,
222
360
  },
223
361
  divider: {
224
- height: 1,
225
- width: '100%',
226
- backgroundColor: '#0052cd0d',
362
+ height: StyleSheet.hairlineWidth,
363
+ marginLeft: 54,
364
+ backgroundColor: '#E4E4E9',
227
365
  },
228
- drawer: {
366
+ sheet: {
229
367
  position: 'absolute',
230
- top: 0,
231
- bottom: 0,
232
- right: 0,
233
- width: width * 0.7,
234
- backgroundColor: '#fff',
235
- padding: 20,
368
+ // Inset rather than flush: the dimmed screen stays visible as a thin
369
+ // line around the sheet.
370
+ left: 3,
371
+ right: 3,
372
+ bottom: 3,
373
+ paddingTop: 8,
374
+ backgroundColor: '#FFFFFF',
375
+ borderRadius: 20,
236
376
  shadowColor: '#000',
237
- shadowOpacity: 0.3,
238
- shadowOffset: { width: -2, height: 0 },
239
- shadowRadius: 5,
240
- elevation: 5,
377
+ shadowOpacity: 0.12,
378
+ shadowOffset: { width: 0, height: -3 },
379
+ shadowRadius: 12,
380
+ elevation: 12,
241
381
  zIndex: 999,
242
382
  },
243
- drawerTitle: {
244
- fontSize: 20,
245
- fontWeight: 'bold',
246
- marginBottom: 20,
383
+ grabArea: {
384
+ alignItems: 'center',
385
+ paddingTop: 6,
386
+ paddingBottom: 12,
387
+ },
388
+ grabber: {
389
+ width: 40,
390
+ height: 4,
391
+ borderRadius: 2,
392
+ backgroundColor: '#C9CBD1',
247
393
  },
248
- drawerItem: {
249
- fontSize: 18,
250
- marginBottom: 10,
394
+ card: {
395
+ overflow: 'hidden',
251
396
  },
252
397
  overlay: {
253
398
  position: 'absolute',