@planningcenter/chat-react-native 3.43.1-qa-858.1 → 3.44.0-rc.0

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 (67) hide show
  1. package/build/components/display/platform_modal_header_buttons.d.ts +14 -42
  2. package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -1
  3. package/build/components/display/platform_modal_header_buttons.js +27 -107
  4. package/build/components/display/platform_modal_header_buttons.js.map +1 -1
  5. package/build/components/primitive/form_sheet.d.ts +2 -8
  6. package/build/components/primitive/form_sheet.d.ts.map +1 -1
  7. package/build/components/primitive/form_sheet.js +4 -10
  8. package/build/components/primitive/form_sheet.js.map +1 -1
  9. package/build/navigation/index.d.ts +149 -76
  10. package/build/navigation/index.d.ts.map +1 -1
  11. package/build/navigation/index.js +76 -67
  12. package/build/navigation/index.js.map +1 -1
  13. package/build/screens/attachment_actions/attachment_actions_screen.d.ts +1 -1
  14. package/build/screens/attachment_actions/attachment_actions_screen.d.ts.map +1 -1
  15. package/build/screens/avatar_picker/avatar_picker_screen.d.ts +2 -2
  16. package/build/screens/avatar_picker/avatar_picker_screen.d.ts.map +1 -1
  17. package/build/screens/bug_report_screen.d.ts.map +1 -1
  18. package/build/screens/bug_report_screen.js +13 -10
  19. package/build/screens/bug_report_screen.js.map +1 -1
  20. package/build/screens/conversation/message_read_receipts_screen.d.ts +1 -1
  21. package/build/screens/conversation/message_read_receipts_screen.d.ts.map +1 -1
  22. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  23. package/build/screens/conversation_details_screen.js +12 -11
  24. package/build/screens/conversation_details_screen.js.map +1 -1
  25. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts +1 -1
  26. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts.map +1 -1
  27. package/build/screens/conversation_filters_screen.d.ts +1 -1
  28. package/build/screens/conversation_filters_screen.d.ts.map +1 -1
  29. package/build/screens/conversation_filters_screen.js +2 -18
  30. package/build/screens/conversation_filters_screen.js.map +1 -1
  31. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
  32. package/build/screens/conversation_new/components/groups_form.js +3 -2
  33. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  34. package/build/screens/conversation_notification_level_select_screen.d.ts +1 -1
  35. package/build/screens/conversation_notification_level_select_screen.d.ts.map +1 -1
  36. package/build/screens/conversation_screen.d.ts.map +1 -1
  37. package/build/screens/conversation_screen.js +2 -6
  38. package/build/screens/conversation_screen.js.map +1 -1
  39. package/build/screens/conversation_select_type_screen.d.ts +1 -1
  40. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  41. package/build/screens/group_notification_level_select_screen.d.ts +1 -1
  42. package/build/screens/group_notification_level_select_screen.d.ts.map +1 -1
  43. package/build/screens/message_actions_screen.d.ts +1 -1
  44. package/build/screens/message_actions_screen.d.ts.map +1 -1
  45. package/build/screens/message_report_screen.d.ts.map +1 -1
  46. package/build/screens/message_report_screen.js +18 -14
  47. package/build/screens/message_report_screen.js.map +1 -1
  48. package/build/screens/notification_settings_screen.d.ts.map +1 -1
  49. package/build/screens/notification_settings_screen.js +14 -0
  50. package/build/screens/notification_settings_screen.js.map +1 -1
  51. package/build/screens/reactions_screen.d.ts +1 -1
  52. package/build/screens/reactions_screen.d.ts.map +1 -1
  53. package/build/screens/send_giphy_screen.d.ts +1 -1
  54. package/build/screens/send_giphy_screen.d.ts.map +1 -1
  55. package/build/screens/system_message_people_screen.d.ts +1 -1
  56. package/build/screens/system_message_people_screen.d.ts.map +1 -1
  57. package/package.json +3 -4
  58. package/src/components/display/platform_modal_header_buttons.tsx +45 -196
  59. package/src/components/primitive/form_sheet.tsx +15 -19
  60. package/src/navigation/index.tsx +151 -147
  61. package/src/screens/bug_report_screen.tsx +15 -16
  62. package/src/screens/conversation_details_screen.tsx +17 -11
  63. package/src/screens/conversation_filters_screen.tsx +2 -25
  64. package/src/screens/conversation_new/components/groups_form.tsx +3 -2
  65. package/src/screens/conversation_screen.tsx +2 -7
  66. package/src/screens/message_report_screen.tsx +21 -20
  67. package/src/screens/notification_settings_screen.tsx +21 -1
@@ -1,16 +1,18 @@
1
+ import { HeaderBackButton } from '@react-navigation/elements'
1
2
  import { StaticParamList } from '@react-navigation/native'
2
3
  import {
3
4
  createNativeStackNavigator,
4
5
  NativeStackHeaderRightProps,
5
- NativeStackNavigationOptions,
6
6
  } from '@react-navigation/native-stack'
7
7
  import { CardStyleInterpolators } from '@react-navigation/stack'
8
8
  import React from 'react'
9
+ import { Platform } from 'react-native'
10
+ import { Icon } from '../components'
9
11
  import {
10
- composeOptions,
11
- withMinimalBack,
12
- withRightClose,
13
- withRightDone,
12
+ composeHeaderOptions,
13
+ createMinimalHeaderBackButton,
14
+ HeaderDoneButton,
15
+ HeaderTextButton,
14
16
  } from '../components/display/platform_modal_header_buttons'
15
17
  import { useDirectMessagesEligible, useQualifiedByAge } from '../hooks'
16
18
  import {
@@ -79,66 +81,64 @@ import {
79
81
  SystemMessagePeopleScreenOptions,
80
82
  } from '../screens/system_message_people_screen'
81
83
  import { TeamConversationScreen } from '../screens/team_conversation_screen'
82
- import { isLiquidGlassEnabled } from '../utils/liquid_glass'
83
84
  import { ScreenLayoutWithChatAccessGate } from './screenLayout'
84
85
 
85
- const globalScreenOptions: () => NativeStackNavigationOptions = () => ({
86
- headerBackButtonDisplayMode: 'minimal',
87
- ...(isLiquidGlassEnabled() ? { headerShadowVisible: false } : {}),
88
- })
89
-
90
86
  export const NewConversationStack = createNativeStackNavigator({
91
87
  initialRouteName: 'ConversationNewEntry',
92
- screenOptions: globalScreenOptions,
88
+ screenOptions: {
89
+ headerBackButtonDisplayMode: 'minimal',
90
+ },
93
91
  screenLayout: ScreenLayoutWithChatAccessGate,
94
92
  screens: {
95
93
  ConversationNewEntry: {
96
94
  screen: ConversationNewEntryScreen,
97
- options: ({ navigation }) =>
98
- composeOptions(
99
- {
100
- title: 'New conversation',
101
- headerBackVisible: false,
102
- },
103
- withRightClose({ onPress: navigation.goBack })
95
+ options: ({ navigation }) => ({
96
+ title: 'New conversation',
97
+ headerRight: (props: NativeStackHeaderRightProps) => (
98
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Cancel" />
104
99
  ),
100
+ headerBackVisible: false,
101
+ }),
105
102
  },
106
103
  ConversationSelectGroupRecipients: {
107
104
  screen: ConversationSelectGroupRecipientsScreen,
108
- options: ({ navigation, route }) =>
109
- composeOptions(
110
- {
111
- title: 'New conversation',
112
- },
113
- withRightClose({
114
- onPress: () => navigation.popTo('Conversations', route.params),
115
- })
105
+ options: ({ navigation, route }) => ({
106
+ title: 'New conversation',
107
+ headerRight: (props: NativeStackHeaderRightProps) => (
108
+ <HeaderTextButton
109
+ {...props}
110
+ onPress={() => navigation.popTo('Conversations', route.params)}
111
+ title="Cancel"
112
+ />
116
113
  ),
114
+ }),
117
115
  },
118
116
  ConversationSelectTeamsILeadRecipients: {
119
117
  screen: ConversationSelectTeamsILeadRecipientsScreen,
120
- options: ({ navigation, route }) =>
121
- composeOptions(
122
- {
123
- title: 'New conversation',
124
- },
125
- withRightClose({
126
- onPress: () => navigation.popTo('Conversations', route.params),
127
- })
118
+ options: ({ navigation, route }) => ({
119
+ title: 'New conversation',
120
+ headerRight: (props: NativeStackHeaderRightProps) => (
121
+ <HeaderTextButton
122
+ {...props}
123
+ onPress={() => navigation.popTo('Conversations', route.params)}
124
+ title="Cancel"
125
+ />
128
126
  ),
127
+ }),
129
128
  },
130
129
  ConversationSelectDirectMessageRecipients: {
131
130
  screen: ConversationSelectDirectMessageRecipientsScreen,
132
131
  if: useDirectMessagesEligible,
133
- options: ({ navigation, route }) =>
134
- composeOptions(
135
- {
136
- title: 'New conversation',
137
- },
138
- withRightClose({
139
- onPress: () => navigation.popTo('Conversations', route.params),
140
- })
132
+ options: ({ navigation, route }) => ({
133
+ title: 'New conversation',
134
+ headerRight: (props: NativeStackHeaderRightProps) => (
135
+ <HeaderTextButton
136
+ {...props}
137
+ onPress={() => navigation.popTo('Conversations', route.params)}
138
+ title="Cancel"
139
+ />
141
140
  ),
141
+ }),
142
142
  },
143
143
  ConversationFilterRecipients: {
144
144
  screen: ConversationFilterRecipientsScreen,
@@ -146,20 +146,21 @@ export const NewConversationStack = createNativeStackNavigator({
146
146
  },
147
147
  ConversationNew: {
148
148
  screen: ConversationNewScreen,
149
- options: ({ navigation, route }) =>
150
- composeOptions(
151
- {
152
- title: 'New conversation',
153
- headerLeft: () => null,
154
- },
155
- withRightClose({
156
- onPress: () => {
149
+ options: ({ navigation, route }) => ({
150
+ title: 'New conversation',
151
+ headerLeft: () => null,
152
+ headerRight: (props: NativeStackHeaderRightProps) => (
153
+ <HeaderTextButton
154
+ {...props}
155
+ onPress={() => {
157
156
  const { chat_group_graph_id, group_source_app_name } =
158
157
  route.params as ConversationSelectRecipientsParams
159
158
  navigation.popTo('Conversations', { chat_group_graph_id, group_source_app_name })
160
- },
161
- })
159
+ }}
160
+ title="Cancel"
161
+ />
162
162
  ),
163
+ }),
163
164
  },
164
165
  AvatarPicker: {
165
166
  screen: AvatarPickerScreen,
@@ -169,19 +170,24 @@ export const NewConversationStack = createNativeStackNavigator({
169
170
  })
170
171
 
171
172
  export const ChatStack = createNativeStackNavigator({
172
- screenOptions: globalScreenOptions,
173
+ screenOptions: {
174
+ headerBackButtonDisplayMode: 'minimal',
175
+ },
173
176
  screenLayout: ScreenLayoutWithChatAccessGate,
174
177
  screens: {
175
178
  Conversations: {
176
179
  screen: ConversationsScreen,
177
- options: ({ route, navigation }) =>
178
- composeOptions(
179
- {
180
- headerTitle: (route.params as { title?: string })?.title ?? 'Chat',
181
- headerBackVisible: false,
182
- },
183
- withRightClose({ onPress: navigation.goBack })
180
+ options: ({ route, navigation }) => ({
181
+ headerTitle: (route.params as { title?: string })?.title ?? 'Chat',
182
+ headerBackVisible: false,
183
+ headerRight: (props: NativeStackHeaderRightProps) => (
184
+ <HeaderBackButton
185
+ backImage={() => <Icon name="general.x" size={18} color={props.tintColor} />}
186
+ onPress={navigation.goBack}
187
+ {...props}
188
+ />
184
189
  ),
190
+ }),
185
191
  },
186
192
  ConversationFilters: {
187
193
  screen: ConversationFiltersScreen,
@@ -189,48 +195,50 @@ export const ChatStack = createNativeStackNavigator({
189
195
  },
190
196
  Conversation: {
191
197
  screen: ConversationScreen,
192
- options: ({ route, navigation }) =>
193
- composeOptions(
194
- {
195
- headerTitle: (props: NativeStackHeaderRightProps) => {
196
- const { conversation_id, title, badge, deleted, muted } =
197
- route.params as ConversationRouteProps
198
+ options: ({ route, navigation }) => ({
199
+ headerTitle: (props: NativeStackHeaderRightProps) => {
200
+ const { conversation_id, title, badge, deleted, muted } =
201
+ route.params as ConversationRouteProps
198
202
 
199
- return (
200
- <ConversationScreenTitle
201
- conversation_id={conversation_id}
202
- badge={badge}
203
- deleted={deleted}
204
- muted={muted}
205
- {...props}
206
- >
207
- {title ?? 'Conversation'}
208
- </ConversationScreenTitle>
209
- )
210
- },
211
- },
212
- withMinimalBack({
213
- onPress: () => {
214
- const params = route.params as ConversationRouteProps
215
- if ((params as ConversationFiltersParams)?.chat_group_graph_id) {
216
- // Ensure that conversations with a graph id pass them back to the conversation list
217
- const { chat_group_graph_id } = params
218
- navigation.popTo('Conversations', { chat_group_graph_id })
219
- } else {
220
- navigation.goBack()
221
- }
222
- },
223
- }),
224
- withRightClose({ onPress: () => navigation.getParent()?.goBack() })
203
+ return (
204
+ <ConversationScreenTitle
205
+ conversation_id={conversation_id}
206
+ badge={badge}
207
+ deleted={deleted}
208
+ muted={muted}
209
+ {...props}
210
+ >
211
+ {title ?? 'Conversation'}
212
+ </ConversationScreenTitle>
213
+ )
214
+ },
215
+ headerRight: (props: NativeStackHeaderRightProps) => (
216
+ <HeaderBackButton
217
+ backImage={() => <Icon name="general.x" size={18} color={props.tintColor} />}
218
+ onPress={() => navigation.getParent()?.goBack()}
219
+ />
225
220
  ),
221
+ headerLeft: createMinimalHeaderBackButton({
222
+ onPress: () => {
223
+ const params = route.params as ConversationRouteProps
224
+ if ((params as ConversationFiltersParams)?.chat_group_graph_id) {
225
+ // Ensure that conversations with a graph id pass them back to the conversation list
226
+ const { chat_group_graph_id } = params
227
+ navigation.popTo('Conversations', { chat_group_graph_id })
228
+ } else {
229
+ navigation.goBack()
230
+ }
231
+ },
232
+ }),
233
+ }),
226
234
  },
227
235
  ConversationReply: {
228
236
  screen: ConversationScreen,
229
237
  options: ({ route, navigation }) =>
230
- composeOptions(
231
- { title: (route.params as ConversationRouteProps)?.title ?? 'Reply' },
232
- withMinimalBack({ onPress: navigation.goBack })
233
- ),
238
+ composeHeaderOptions({
239
+ title: (route.params as ConversationRouteProps)?.title ?? 'Reply',
240
+ onPress: navigation.goBack,
241
+ }),
234
242
  },
235
243
  TeamConversation: {
236
244
  screen: TeamConversationScreen,
@@ -243,14 +251,13 @@ export const ChatStack = createNativeStackNavigator({
243
251
  },
244
252
  ConversationDetails: {
245
253
  screen: ConversationDetailsScreen,
246
- options: ({ navigation }) =>
247
- composeOptions(
248
- {
249
- presentation: 'modal',
250
- title: 'Conversation details',
251
- },
252
- withRightDone({ onPress: navigation.goBack })
254
+ options: ({ navigation }) => ({
255
+ presentation: 'modal',
256
+ title: 'Conversation details',
257
+ headerRight: (props: NativeStackHeaderRightProps) => (
258
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
253
259
  ),
260
+ }),
254
261
  },
255
262
  AvatarPicker: {
256
263
  screen: AvatarPickerScreen,
@@ -258,43 +265,38 @@ export const ChatStack = createNativeStackNavigator({
258
265
  },
259
266
  ChatSettings: {
260
267
  screen: SettingsScreen,
261
- options: ({ navigation }) =>
262
- composeOptions({ title: 'Chat settings' }, withMinimalBack({ onPress: navigation.goBack })),
268
+ options: ({ navigation }) => ({
269
+ title: 'Chat settings',
270
+ headerBackVisible: false,
271
+ headerRight: (props: NativeStackHeaderRightProps) => (
272
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
273
+ ),
274
+ }),
263
275
  },
264
276
  NotificationSettings: {
265
277
  screen: NotificationSettingsScreen,
266
- options: ({ navigation }) =>
267
- navigation.getState().index === 0
268
- ? composeOptions(
269
- { title: 'Chat notifications' },
270
- withRightClose({ onPress: navigation.goBack })
271
- )
272
- : composeOptions(
273
- { title: 'Chat notifications' },
274
- withMinimalBack({ onPress: navigation.goBack })
275
- ),
278
+ options: ({ navigation }) => ({
279
+ title: 'Chat',
280
+ headerBackVisible: false,
281
+ headerRight: (props: NativeStackHeaderRightProps) => (
282
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
283
+ ),
284
+ }),
276
285
  },
277
286
  PreferredAppSelection: {
278
287
  screen: PreferredAppSelectionScreen,
279
- options: ({ navigation }) =>
280
- composeOptions({ title: 'Preferred app' }, withMinimalBack({ onPress: navigation.goBack })),
288
+ options: {
289
+ title: 'Preferred app',
290
+ },
281
291
  },
282
292
  GroupNotificationSettings: {
283
293
  screen: GroupNotificationSettingsScreen,
284
- options: ({ route, navigation }) => {
285
- const title = (route.params as { title?: string })?.title || 'Group Settings'
286
-
287
- // The dismiss button only shows when this is the entry screen (e.g.
288
- // deep links); deeper in the stack the back button covers dismissal.
289
- return navigation.getState().index === 0
290
- ? composeOptions(
291
- {
292
- title,
293
- },
294
- withRightClose({ onPress: navigation.goBack })
295
- )
296
- : composeOptions({ title }, withMinimalBack({ onPress: navigation.goBack }))
297
- },
294
+ options: ({ route, navigation }) => ({
295
+ title: (route.params as { title?: string })?.title || 'Group Settings',
296
+ headerRight: (props: NativeStackHeaderRightProps) => (
297
+ <HeaderDoneButton {...props} navigation={navigation} />
298
+ ),
299
+ }),
298
300
  },
299
301
  GroupNotificationLevelSelect: {
300
302
  screen: GroupNotificationLevelSelectScreen,
@@ -315,14 +317,17 @@ export const ChatStack = createNativeStackNavigator({
315
317
  GroupConversationNew: {
316
318
  screen: ConversationNewScreen,
317
319
  if: useQualifiedByAge,
318
- options: ({ navigation }) =>
319
- composeOptions(
320
- {
321
- title: 'New conversation',
322
- headerLeft: () => null,
323
- },
324
- withRightClose({ onPress: () => navigation.getParent()?.goBack() })
320
+ options: ({ navigation }) => ({
321
+ title: 'New conversation',
322
+ headerLeft: () => null,
323
+ headerRight: props => (
324
+ <HeaderTextButton
325
+ {...props}
326
+ onPress={() => navigation.getParent()?.goBack()}
327
+ title="Cancel"
328
+ />
325
329
  ),
330
+ }),
326
331
  },
327
332
  SendGiphy: {
328
333
  screen: SendGiphyScreen,
@@ -363,15 +368,14 @@ export const ChatStack = createNativeStackNavigator({
363
368
  },
364
369
  GetHelp: {
365
370
  screen: GetHelpScreen,
366
- options: ({ navigation }) =>
367
- composeOptions(
368
- {
369
- headerTitle: 'Get help',
370
- headerBackVisible: false,
371
- presentation: 'modal',
372
- },
373
- withRightClose({ onPress: navigation.goBack })
371
+ options: ({ navigation }) => ({
372
+ headerTitle: 'Get help',
373
+ headerBackVisible: false,
374
+ presentation: 'modal',
375
+ headerRight: props => (
376
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Close" />
374
377
  ),
378
+ }),
375
379
  },
376
380
  NotFound: {
377
381
  screen: NotFound,
@@ -4,7 +4,7 @@ import type {
4
4
  NativeStackScreenProps,
5
5
  } from '@react-navigation/native-stack'
6
6
  import { startsWith } from 'lodash'
7
- import React, { useCallback, useState } from 'react'
7
+ import React, { useCallback, useLayoutEffect, useState } from 'react'
8
8
  import {
9
9
  View,
10
10
  StyleSheet,
@@ -25,10 +25,8 @@ import {
25
25
  KeyboardView,
26
26
  } from '../components'
27
27
  import {
28
- composeOptions,
29
28
  HeaderDismissButton,
30
- useHeaderRight,
31
- withLeftClose,
29
+ HeaderTextButton,
32
30
  } from '../components/display/platform_modal_header_buttons'
33
31
  import { VideoAttachmentPreview } from '../components/display/video_attachment_preview'
34
32
  import { DefaultLoading } from '../components/page/loading'
@@ -57,11 +55,11 @@ enum BUG_TYPE_OPTIONS {
57
55
 
58
56
  export const BugReportScreenOptions = ({
59
57
  navigation,
60
- }: NativeStackScreenProps<any>): NativeStackNavigationOptions =>
61
- composeOptions(
62
- { presentation: 'modal', title: 'Report a bug' },
63
- withLeftClose({ onPress: () => navigation.goBack() })
64
- )
58
+ }: NativeStackScreenProps<any>): NativeStackNavigationOptions => ({
59
+ presentation: 'modal',
60
+ title: 'Report a bug',
61
+ headerLeft: () => <HeaderDismissButton title="Cancel" onPress={() => navigation.goBack()} />,
62
+ })
65
63
 
66
64
  interface Attachment {
67
65
  id: string
@@ -158,13 +156,14 @@ export function BugReportScreen() {
158
156
  return ImagePicker.openImageLibraryAsync().then(result => uploadImagePickerResult(result))
159
157
  }
160
158
 
161
- useHeaderRight({
162
- icon: 'general.upArrow',
163
- accessibilityLabel: 'Submit',
164
- prominent: true,
165
- onPress: handleSubmit,
166
- disabled: !formValid,
167
- })
159
+ useLayoutEffect(() => {
160
+ navigation.setOptions({
161
+ // eslint-disable-next-line react/no-unstable-nested-components
162
+ headerRight: () => (
163
+ <HeaderTextButton title="Submit" onPress={handleSubmit} disabled={!formValid} />
164
+ ),
165
+ })
166
+ }, [formValid, handleSubmit, navigation])
168
167
 
169
168
  if (status === 'pending') {
170
169
  return (
@@ -38,7 +38,7 @@ import {
38
38
  type TextStyle,
39
39
  } from '../components'
40
40
  import { ConversationAvatar } from '../components/display/conversation_avatar'
41
- import { useHeaderRight } from '../components/display/platform_modal_header_buttons'
41
+ import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
42
42
  import { ButtonAppearanceUnion } from '../components/display/utils/button_colors'
43
43
  import { useSuspensePaginator, useTheme } from '../hooks'
44
44
  import {
@@ -222,18 +222,24 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
222
222
  [name, productName, resourceType, styles.headerTitleBadge, styles.headerTitleContainer]
223
223
  )
224
224
 
225
- useHeaderRight({
226
- icon: 'general.check',
227
- accessibilityLabel: 'Done',
228
- onPress: () => {
229
- saveTitle({ title: trimmedTitle || conversation.title })
230
- navigation.goBack()
231
- },
232
- })
225
+ const HeaderRight = useCallback(() => {
226
+ return (
227
+ <HeaderTextButton
228
+ onPress={() => {
229
+ saveTitle({ title: trimmedTitle || conversation.title })
230
+ navigation.goBack()
231
+ }}
232
+ title="Done"
233
+ />
234
+ )
235
+ }, [conversation.title, navigation, saveTitle, trimmedTitle])
233
236
 
234
237
  useEffect(() => {
235
- navigation.setOptions({ headerTitle: HeaderTitle })
236
- }, [HeaderTitle, navigation])
238
+ navigation.setOptions({
239
+ headerRight: HeaderRight,
240
+ headerTitle: HeaderTitle,
241
+ })
242
+ }, [HeaderRight, HeaderTitle, navigation])
237
243
 
238
244
  const listData = [
239
245
  {
@@ -1,6 +1,5 @@
1
1
  import { useHeaderHeight } from '@react-navigation/elements'
2
- import * as ReactNavigationNative from '@react-navigation/native'
3
- import { RouteProp, useRoute } from '@react-navigation/native'
2
+ import { createComponentForStaticNavigation, RouteProp, useRoute } from '@react-navigation/native'
4
3
  import { createNativeStackNavigator } from '@react-navigation/native-stack'
5
4
  import React, { useCallback } from 'react'
6
5
  import { LayoutChangeEvent, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
@@ -59,26 +58,7 @@ const FilterNavigator = createNativeStackNavigator<ConversationFilterStackParamL
59
58
  },
60
59
  })
61
60
 
62
- // tree.getComponent() doesn't exist on every host's installed
63
- // react-navigation/core — hosts on an older version would throw here.
64
- // Where it does exist, it's the real implementation (the "deprecated"
65
- // createComponentForStaticNavigation is just a console.warn wrapper around
66
- // the same call on current versions), so prefer it and only reach for the
67
- // old function on cores where getComponent() genuinely isn't there yet.
68
- function createStaticNavigationComponent<P extends object>(
69
- tree: { getComponent?: () => React.ComponentType<P> },
70
- name: string
71
- ): React.ComponentType<P> {
72
- if (typeof tree.getComponent === 'function') return tree.getComponent()
73
-
74
- const { createComponentForStaticNavigation } = ReactNavigationNative as {
75
- createComponentForStaticNavigation: (tree: unknown, name: string) => React.ComponentType<P>
76
- }
77
-
78
- return createComponentForStaticNavigation(tree, name)
79
- }
80
-
81
- const Filters = createStaticNavigationComponent(FilterNavigator, 'Filters')
61
+ const Filters = createComponentForStaticNavigation(FilterNavigator, 'Filters')
82
62
 
83
63
  export const ConversationFiltersScreen = (_props: ConversationFiltersScreenProps) => {
84
64
  const styles = useStyles()
@@ -137,9 +117,6 @@ const useStyles = () => {
137
117
  ios: 20,
138
118
  android: 20 + top,
139
119
  }),
140
- // The filter list scrolls under it, so the sheet header doesn't need a
141
- // separator the way the non-scrolling reaction sheet does.
142
- borderBottomWidth: 0,
143
120
  },
144
121
  })
145
122
  }
@@ -4,6 +4,7 @@ import { Platform, Pressable, StyleSheet, TextInput, View } from 'react-native'
4
4
  import { Banner, ChildNotice, Heading, Text } from '../../../components'
5
5
  import { ActionButton } from '../../../components/display/action_button'
6
6
  import { KeyboardView } from '../../../components/display/keyboard_view'
7
+ import { AutoFocusAwareTextInput } from '../../../components/display/text_input'
7
8
  import { useApiClient, useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks'
8
9
  import { useGroupChatConversationPayload } from '../../../hooks/groups/use_group_chat_conversation_payload'
9
10
  import {
@@ -212,13 +213,13 @@ function FormContent({
212
213
  <Divider />
213
214
  <Pressable style={styles.titleSection} onPress={handleTitleSectionPress}>
214
215
  <Heading variant="h3">Title</Heading>
215
- <TextInput
216
+ <AutoFocusAwareTextInput
216
217
  placeholder="Topic of conversation (required)"
217
218
  value={title}
218
219
  onChangeText={setTitle}
219
220
  style={styles.titleInput}
220
221
  autoFocus={true}
221
- ref={inputRef}
222
+ inputRef={inputRef}
222
223
  />
223
224
  </Pressable>
224
225
  <Divider />
@@ -9,7 +9,7 @@ import {
9
9
  useRoute,
10
10
  } from '@react-navigation/native'
11
11
  import React, { useCallback, useEffect, useRef, useState } from 'react'
12
- import { FlatList, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
12
+ import { FlatList, Platform, StyleSheet, View } from 'react-native'
13
13
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
14
14
  import { Badge, Icon, Text } from '../components'
15
15
  import { ConversationStartBanner } from '../components/conversation/conversation_start_banner'
@@ -25,7 +25,6 @@ import { ReplyShadowMessage } from '../components/conversation/reply_shadow_mess
25
25
  import { SystemMessage } from '../components/conversation/system_message'
26
26
  import { TypingIndicator } from '../components/conversation/typing_indicator'
27
27
  import { KeyboardView } from '../components/display/keyboard_view'
28
- import { useHeaderSlotReserve } from '../components/display/platform_modal_header_buttons'
29
28
  import BlankState from '../components/primitive/blank_state_primitive'
30
29
  import { ConversationContextProvider } from '../contexts/conversation_context'
31
30
  import { useTheme } from '../hooks'
@@ -375,15 +374,11 @@ export const ConversationScreenTitle = ({
375
374
  }
376
375
 
377
376
  const usePressableHeaderStyle = () => {
378
- const { width } = useWindowDimensions()
379
- const slotReserve = useHeaderSlotReserve()
380
- const headerContainerStyle = { maxWidth: width - slotReserve * 2 }
381
-
382
377
  return StyleSheet.create({
383
378
  container: {
384
379
  alignItems: Platform.select({ android: 'flex-start', default: 'center' }),
380
+ marginRight: Platform.select({ ios: 20, default: 16 }),
385
381
  flex: 1,
386
- ...headerContainerStyle,
387
382
  },
388
383
  titleWrapper: {
389
384
  alignItems: 'center',