@ethora/chat-component-rn 26.7.1 → 26.7.3

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 (127) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +22 -0
  3. package/lib/commonjs/assets/icons.js +2 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/MainComponents/ChatRoom.js +60 -3
  6. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/ChatWrapper.js +18 -0
  8. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/MessageList.js +9 -3
  10. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  11. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +110 -37
  12. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  13. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +16 -14
  14. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  15. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +130 -125
  16. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  17. package/lib/commonjs/components/styled/SendInput.js +0 -10
  18. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  19. package/lib/commonjs/context/xmppProvider.js +12 -0
  20. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  21. package/lib/commonjs/helpers/historyPreloadScheduler.js +65 -2
  22. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  23. package/lib/commonjs/helpers/shallowEqual.js +36 -0
  24. package/lib/commonjs/helpers/shallowEqual.js.map +1 -0
  25. package/lib/commonjs/hooks/useChatWrapperInit.js +15 -0
  26. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  27. package/lib/commonjs/hooks/useComposing.js +27 -0
  28. package/lib/commonjs/hooks/useComposing.js.map +1 -1
  29. package/lib/commonjs/hooks/useSendMessage.js +27 -1
  30. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  31. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +6 -1
  32. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  33. package/lib/commonjs/main.js +6 -0
  34. package/lib/commonjs/main.js.map +1 -1
  35. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +6 -2
  36. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  37. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  38. package/lib/commonjs/roomStore/roomsSlice.js +2 -2
  39. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  40. package/lib/module/assets/icons.js +1 -1
  41. package/lib/module/assets/icons.js.map +1 -1
  42. package/lib/module/components/MainComponents/ChatRoom.js +61 -4
  43. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  44. package/lib/module/components/MainComponents/ChatWrapper.js +19 -1
  45. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  46. package/lib/module/components/MainComponents/MessageList.js +9 -3
  47. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  48. package/lib/module/components/Menu/HeaderRoomListMenu.js +110 -38
  49. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  50. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +16 -14
  51. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  52. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +130 -125
  53. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  54. package/lib/module/components/styled/SendInput.js +1 -11
  55. package/lib/module/components/styled/SendInput.js.map +1 -1
  56. package/lib/module/context/xmppProvider.js +12 -0
  57. package/lib/module/context/xmppProvider.js.map +1 -1
  58. package/lib/module/helpers/historyPreloadScheduler.js +66 -3
  59. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  60. package/lib/module/helpers/shallowEqual.js +31 -0
  61. package/lib/module/helpers/shallowEqual.js.map +1 -0
  62. package/lib/module/hooks/useChatWrapperInit.js +15 -0
  63. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  64. package/lib/module/hooks/useComposing.js +28 -1
  65. package/lib/module/hooks/useComposing.js.map +1 -1
  66. package/lib/module/hooks/useSendMessage.js +28 -2
  67. package/lib/module/hooks/useSendMessage.js.map +1 -1
  68. package/lib/module/hooks/useUnreadMessagesCounter.js +6 -1
  69. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  70. package/lib/module/main.js +1 -1
  71. package/lib/module/main.js.map +1 -1
  72. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +6 -2
  73. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  74. package/lib/module/networking/xmppClient.js.map +1 -1
  75. package/lib/module/roomStore/roomsSlice.js +1 -1
  76. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  77. package/lib/typescript/assets/icons.d.ts +4 -0
  78. package/lib/typescript/assets/icons.d.ts.map +1 -1
  79. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  80. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  81. package/lib/typescript/components/MainComponents/MessageList.d.ts +10 -1
  82. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  83. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +3 -0
  84. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  85. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  86. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  87. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  88. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  89. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  90. package/lib/typescript/helpers/shallowEqual.d.ts +11 -0
  91. package/lib/typescript/helpers/shallowEqual.d.ts.map +1 -0
  92. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  93. package/lib/typescript/hooks/useComposing.d.ts.map +1 -1
  94. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  95. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
  96. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
  97. package/lib/typescript/main.d.ts +1 -1
  98. package/lib/typescript/main.d.ts.map +1 -1
  99. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +1 -0
  100. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
  101. package/lib/typescript/networking/xmppClient.d.ts +1 -0
  102. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  103. package/lib/typescript/roomStore/roomsSlice.d.ts +1 -0
  104. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  105. package/lib/typescript/types/types.d.ts +13 -0
  106. package/lib/typescript/types/types.d.ts.map +1 -1
  107. package/package.json +1 -1
  108. package/src/assets/icons.tsx +19 -0
  109. package/src/components/MainComponents/ChatRoom.tsx +63 -1
  110. package/src/components/MainComponents/ChatWrapper.tsx +19 -1
  111. package/src/components/MainComponents/MessageList.tsx +19 -2
  112. package/src/components/Menu/HeaderRoomListMenu.tsx +105 -11
  113. package/src/components/Modals/AttachSheet/AttachSheet.tsx +16 -14
  114. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +8 -6
  115. package/src/components/styled/SendInput.tsx +0 -10
  116. package/src/context/xmppProvider.tsx +14 -0
  117. package/src/helpers/historyPreloadScheduler.ts +80 -3
  118. package/src/helpers/shallowEqual.ts +33 -0
  119. package/src/hooks/useChatWrapperInit.ts +15 -0
  120. package/src/hooks/useComposing.tsx +37 -1
  121. package/src/hooks/useSendMessage.tsx +32 -2
  122. package/src/hooks/useUnreadMessagesCounter.ts +11 -0
  123. package/src/main.ts +1 -1
  124. package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +17 -3
  125. package/src/networking/xmppClient.ts +5 -1
  126. package/src/roomStore/roomsSlice.ts +1 -1
  127. package/src/types/types.ts +22 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this pr
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ### Added
9
+
10
+ - **`config.logout` — built-in "Sign out" item in the room-list header menu.** `{ enabled, label?, confirm?, onBeforeLogout?, onAfterLogout? }`. Rendered last (after New Chat / Profile / Settings) with a logout icon tinted `colors.primary`; hidden unless `enabled: true`, so existing menus are unchanged. Tap flow: close drawer → native confirm (`confirm` defaults to `true`; pass an object to customise title/message/button copy, `false` to skip) → `await onBeforeLogout?.()` (return `false` to cancel) → `await logoutService.performLogout()` (full teardown: XMPP, redux, persisted slices, AsyncStorage, REST cache) → `await onAfterLogout?.()` for the host's own session/navigation logout. Host callback errors are caught and logged via `console.warn` — a throwing `onBeforeLogout` cancels, a throwing `onAfterLogout` is swallowed after the teardown has landed. Documented in README ("Logging out") and `instructions.md`. Tests in `headerRoomListMenuLogout.test.tsx`.
11
+ - **`useLogout` is now exported from the package root** (previously only `logoutService`), so a host can build its own button with the same awaitable teardown.
12
+
13
+ ### Fixed
14
+
15
+ - **iOS: attach-sheet rows (Take photo / Photo or video / Document) did nothing, and the next tap threw `PickingInProgressException: Different document picking in progress`.** The picker handler was invoked from the exit-animation completion callback in the same tick as `setMounted(false)` — but that only *starts* RN `<Modal>`'s native dismiss, so the sheet's UIViewController was still on screen when `expo-image-picker` / `expo-document-picker` called `currentViewController().present(picker)`. UIKit silently dropped the present, the promise never resolved, and expo-document-picker kept its `pickingContext` stuck. `AttachSheet` now fires the pending handler from `<Modal onDismiss>` on iOS (the only signal that the view controller is really gone); Android, where `onDismiss` never fires, keeps running it from the animation callback. The handler is nulled before invocation so it runs at most once, and an interrupted animation (`finished: false`) still does nothing. Tests in `attachSheetPendingHandler.test.tsx`. On iOS, picker rows also skip the sheet's slide-down (the modal is hidden immediately, so `onDismiss` arrives ~50 ms after the tap instead of ~300 ms); Cancel and backdrop taps keep the animated close. The old 350 ms iOS `setTimeout` in `SendInput.handleFileSelection` that tried to paper over the same race is removed — the Document picker now opens as soon as the sheet is gone instead of noticeably later.
16
+
8
17
  ### Security
9
18
 
10
19
  - **Chat tokens, the XMPP password, and message history are no longer stored in plaintext AsyncStorage.** All four bearer credentials on `User` (REST access + refresh token, XMPP password, secure-media fileToken) now go through the platform Keychain (iOS) / Keystore-backed EncryptedSharedPreferences (Android) via the optional `expo-secure-store` peer dependency, instead of sitting in AsyncStorage's plain SQLite/plist storage. The persisted message-history and room-list cache (`roomStore/persistence.ts`) is now AES-256-CBC encrypted at rest, with the symmetric key itself held in that same secure store — envelope encryption, since bulk history is too large (and unbounded) for direct Keychain storage. `expo-secure-store` is optional (mirrors `expo-video`/`expo-audio` etc.): a host that hasn't added it falls back to namespaced-but-still-unencrypted AsyncStorage with one logged warning, so nothing breaks for existing consumers, but the secure path is what ships by default for any host on the standard Expo dependency set.
package/README.md CHANGED
@@ -271,6 +271,28 @@ function SignOutButton() {
271
271
  }
272
272
  ```
273
273
 
274
+ ### Built-in "Sign out" menu item
275
+
276
+ Don't want to build your own button? Enable the item in the room-list header menu (the drawer with New Chat / Profile / Settings). It renders last, tinted with `config.colors.primary`, and runs the same awaitable teardown as `useLogout()`:
277
+
278
+ ```tsx
279
+ <Chat
280
+ config={{
281
+ logout: {
282
+ enabled: true,
283
+ label: 'Sign out', // default
284
+ confirm: { message: 'Sign out of chat?' }, // `true` (default) uses stock copy, `false` skips the dialog
285
+ onBeforeLogout: async () => {
286
+ // return false to cancel (e.g. unsaved draft guard)
287
+ },
288
+ onAfterLogout: () => navigation.replace('SignIn'), // runs AFTER the full teardown
289
+ },
290
+ }}
291
+ />
292
+ ```
293
+
294
+ Tap flow: close drawer → confirmation (native `Alert`) → `await onBeforeLogout?.()` (`false` cancels) → `await logoutService.performLogout()` → `await onAfterLogout?.()`. The host-side session/navigation logout belongs in `onAfterLogout` — by the time it runs, XMPP is disconnected and every persisted key is gone. Errors thrown by either callback are caught and logged via `console.warn`; a throwing `onBeforeLogout` cancels the logout. With `enabled: false` (or the option omitted) the menu is unchanged.
295
+
274
296
  Why awaitable: the persistence layer debounces writes by 200 ms, and the chat slice removes its persisted user fire-and-forget. If the host navigated / re-mounted `<Chat>` immediately after a non-awaited call, the next bootstrap could occasionally rehydrate stale state ("old chats reappear"). Awaiting the returned promise eliminates that race. The function never rejects — any internal failure is logged via `console.warn`, so a non-awaited call still won't crash the host. For non-React contexts you can call `logoutService.performLogout()` directly (same Promise).
275
297
 
276
298
  ## Customization flags worth knowing