@planningcenter/chat-react-native 3.43.1-qa-staging.1 → 3.44.0-rc.1
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.
- package/build/components/display/platform_modal_header_buttons.d.ts +42 -14
- package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -1
- package/build/components/display/platform_modal_header_buttons.js +107 -27
- package/build/components/display/platform_modal_header_buttons.js.map +1 -1
- package/build/components/primitive/form_sheet.d.ts +8 -2
- package/build/components/primitive/form_sheet.d.ts.map +1 -1
- package/build/components/primitive/form_sheet.js +10 -4
- package/build/components/primitive/form_sheet.js.map +1 -1
- package/build/navigation/index.d.ts +76 -149
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +67 -76
- package/build/navigation/index.js.map +1 -1
- package/build/screens/attachment_actions/attachment_actions_screen.d.ts +1 -1
- package/build/screens/attachment_actions/attachment_actions_screen.d.ts.map +1 -1
- package/build/screens/avatar_picker/avatar_picker_screen.d.ts +2 -2
- package/build/screens/avatar_picker/avatar_picker_screen.d.ts.map +1 -1
- package/build/screens/bug_report_screen.d.ts.map +1 -1
- package/build/screens/bug_report_screen.js +10 -13
- package/build/screens/bug_report_screen.js.map +1 -1
- package/build/screens/conversation/message_read_receipts_screen.d.ts +1 -1
- package/build/screens/conversation/message_read_receipts_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +11 -12
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts +1 -1
- package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_filters_screen.d.ts +1 -1
- package/build/screens/conversation_filters_screen.d.ts.map +1 -1
- package/build/screens/conversation_filters_screen.js +18 -2
- package/build/screens/conversation_filters_screen.js.map +1 -1
- package/build/screens/conversation_notification_level_select_screen.d.ts +1 -1
- package/build/screens/conversation_notification_level_select_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +6 -2
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_type_screen.d.ts +1 -1
- package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
- package/build/screens/group_notification_level_select_screen.d.ts +1 -1
- package/build/screens/group_notification_level_select_screen.d.ts.map +1 -1
- package/build/screens/message_actions_screen.d.ts +1 -1
- package/build/screens/message_actions_screen.d.ts.map +1 -1
- package/build/screens/message_report_screen.d.ts.map +1 -1
- package/build/screens/message_report_screen.js +18 -20
- package/build/screens/message_report_screen.js.map +1 -1
- package/build/screens/notification_settings_screen.d.ts.map +1 -1
- package/build/screens/notification_settings_screen.js +0 -14
- package/build/screens/notification_settings_screen.js.map +1 -1
- package/build/screens/reactions_screen.d.ts +1 -1
- package/build/screens/reactions_screen.d.ts.map +1 -1
- package/build/screens/send_giphy_screen.d.ts +1 -1
- package/build/screens/send_giphy_screen.d.ts.map +1 -1
- package/build/screens/system_message_people_screen.d.ts +1 -1
- package/build/screens/system_message_people_screen.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/components/display/platform_modal_header_buttons.tsx +196 -45
- package/src/components/primitive/form_sheet.tsx +19 -15
- package/src/navigation/index.tsx +147 -151
- package/src/screens/bug_report_screen.tsx +16 -15
- package/src/screens/conversation_details_screen.tsx +11 -17
- package/src/screens/conversation_filters_screen.tsx +25 -2
- package/src/screens/conversation_screen.tsx +7 -2
- package/src/screens/message_report_screen.tsx +24 -23
- package/src/screens/notification_settings_screen.tsx +1 -21
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { HeaderBackButton, HeaderButton } from '@react-navigation/elements'
|
|
1
|
+
import { HeaderBackButton, HeaderButton, PlatformPressable } from '@react-navigation/elements'
|
|
2
|
+
import { useNavigation } from '@react-navigation/native'
|
|
2
3
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
NativeStackHeaderItemProps,
|
|
5
|
+
NativeStackNavigationOptions,
|
|
5
6
|
} from '@react-navigation/native-stack'
|
|
7
|
+
import { useLayoutEffect } from 'react'
|
|
6
8
|
import { ColorValue, Platform, StyleSheet } from 'react-native'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
9
|
+
import type { SFSymbol } from 'sf-symbols-typescript'
|
|
10
|
+
import { useFontScale, useTheme } from '../../hooks'
|
|
11
|
+
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
|
|
12
|
+
import { Icon, type IconString } from './icon'
|
|
10
13
|
import { TextButton } from './text_button'
|
|
11
14
|
|
|
12
15
|
interface HeaderTextButtonProps {
|
|
@@ -67,61 +70,209 @@ export const HeaderDismissButton = ({
|
|
|
67
70
|
})
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
const createTextHeaderRight =
|
|
74
|
+
({ onPress, title, disabled }: HeaderTextButtonProps) =>
|
|
75
|
+
(props: NativeStackHeaderItemProps) => (
|
|
76
|
+
<HeaderTextButton {...props} onPress={onPress} title={title} disabled={disabled} />
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
export type OptionsDecorator = (
|
|
80
|
+
options: NativeStackNavigationOptions
|
|
81
|
+
) => NativeStackNavigationOptions
|
|
82
|
+
|
|
83
|
+
export const composeOptions = (
|
|
84
|
+
base: NativeStackNavigationOptions,
|
|
85
|
+
...decorators: OptionsDecorator[]
|
|
86
|
+
): NativeStackNavigationOptions => decorators.reduce((options, decorate) => decorate(options), base)
|
|
87
|
+
|
|
88
|
+
interface TextButtonDecoratorProps {
|
|
89
|
+
text: string
|
|
90
|
+
onPress: () => void
|
|
91
|
+
disabled?: boolean
|
|
72
92
|
}
|
|
73
93
|
|
|
74
|
-
export const
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
export const withRightText =
|
|
95
|
+
({ text, onPress, disabled }: TextButtonDecoratorProps): OptionsDecorator =>
|
|
96
|
+
options => ({
|
|
97
|
+
...options,
|
|
98
|
+
headerRight: createTextHeaderRight({ onPress, title: text, disabled }),
|
|
99
|
+
unstable_headerRightItems: () => [{ type: 'button' as const, label: text, onPress, disabled }],
|
|
100
|
+
})
|
|
77
101
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
const HEADER_ICON_SIZE = 17
|
|
103
|
+
const HEADER_GLASS_BUTTON_SIZE = 44
|
|
104
|
+
const HEADER_BAR_INSET = 16
|
|
105
|
+
const HEADER_SLOT_GAP = 12
|
|
81
106
|
|
|
82
|
-
|
|
107
|
+
export const useHeaderSlotReserve = (): number => {
|
|
108
|
+
const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER_LANDMARK })
|
|
109
|
+
|
|
110
|
+
return HEADER_BAR_INSET + HEADER_GLASS_BUTTON_SIZE * fontScale + HEADER_SLOT_GAP
|
|
83
111
|
}
|
|
84
112
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
113
|
+
const HEADER_FALLBACK_HIT_SLOP = 14
|
|
114
|
+
|
|
115
|
+
const iconStyles = StyleSheet.create({
|
|
116
|
+
disabled: {
|
|
117
|
+
opacity: 0.4,
|
|
118
|
+
},
|
|
119
|
+
fallbackButton: {
|
|
120
|
+
alignItems: 'center',
|
|
121
|
+
justifyContent: 'center',
|
|
122
|
+
paddingHorizontal: 8,
|
|
123
|
+
},
|
|
124
|
+
fallbackButtonLeft: {
|
|
125
|
+
marginRight: Platform.select({ android: 16, default: 0 }),
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
const SF_SYMBOL_NAMES: Partial<Record<IconString, SFSymbol>> = {
|
|
130
|
+
'general.x': 'xmark',
|
|
131
|
+
'general.check': 'checkmark',
|
|
132
|
+
'general.upArrow': 'arrow.up',
|
|
133
|
+
'general.leftChevron': 'chevron.left',
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const sfSymbolFor = (icon: IconString): SFSymbol => {
|
|
137
|
+
const name = SF_SYMBOL_NAMES[icon]
|
|
138
|
+
|
|
139
|
+
if (!name) throw new Error(`No SF Symbol mapped for icon "${icon}" — add one to SF_SYMBOL_NAMES.`)
|
|
140
|
+
|
|
141
|
+
return name
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface HeaderIconProps {
|
|
145
|
+
icon: IconString
|
|
146
|
+
accessibilityLabel: string
|
|
147
|
+
onPress: () => void
|
|
148
|
+
disabled?: boolean
|
|
149
|
+
prominent?: boolean
|
|
150
|
+
tintColor?: ColorValue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const createHeaderIconItem = ({
|
|
154
|
+
icon,
|
|
155
|
+
accessibilityLabel,
|
|
156
|
+
onPress,
|
|
157
|
+
disabled,
|
|
158
|
+
prominent,
|
|
159
|
+
tintColor,
|
|
160
|
+
}: HeaderIconProps) => ({
|
|
161
|
+
type: 'button' as const,
|
|
162
|
+
label: '',
|
|
163
|
+
accessibilityLabel,
|
|
164
|
+
onPress,
|
|
165
|
+
disabled,
|
|
166
|
+
icon: { type: 'sfSymbol' as const, name: sfSymbolFor(icon) },
|
|
167
|
+
...(prominent ? { variant: 'prominent' as const, tintColor } : {}),
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const createHeaderIconElement =
|
|
171
|
+
(position: 'left' | 'right') =>
|
|
172
|
+
({ icon, accessibilityLabel, onPress, disabled, tintColor }: HeaderIconProps) =>
|
|
173
|
+
() => (
|
|
174
|
+
<PlatformPressable
|
|
175
|
+
onPress={onPress}
|
|
176
|
+
disabled={disabled}
|
|
177
|
+
hitSlop={HEADER_FALLBACK_HIT_SLOP}
|
|
178
|
+
accessibilityRole="button"
|
|
179
|
+
accessibilityLabel={accessibilityLabel}
|
|
180
|
+
style={[
|
|
181
|
+
iconStyles.fallbackButton,
|
|
182
|
+
position === 'left' && iconStyles.fallbackButtonLeft,
|
|
183
|
+
disabled && iconStyles.disabled,
|
|
184
|
+
]}
|
|
185
|
+
>
|
|
186
|
+
<Icon name={icon} size={HEADER_ICON_SIZE} color={tintColor} />
|
|
187
|
+
</PlatformPressable>
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
export const withRightIcon =
|
|
191
|
+
(props: HeaderIconProps): OptionsDecorator =>
|
|
192
|
+
options => ({
|
|
193
|
+
...options,
|
|
194
|
+
headerRight: createHeaderIconElement('right')(props),
|
|
195
|
+
unstable_headerRightItems: () => [createHeaderIconItem(props)],
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
export const withLeftIcon =
|
|
199
|
+
(props: HeaderIconProps): OptionsDecorator =>
|
|
200
|
+
options => ({
|
|
201
|
+
...options,
|
|
202
|
+
headerLeft: createHeaderIconElement('left')(props),
|
|
203
|
+
unstable_headerLeftItems: () => [createHeaderIconItem(props)],
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
export const withRightClose = ({ onPress }: { onPress: () => void }) =>
|
|
207
|
+
withRightIcon({ icon: 'general.x', accessibilityLabel: 'Close', onPress })
|
|
208
|
+
|
|
209
|
+
export const withLeftClose = ({ onPress }: { onPress: () => void }) =>
|
|
210
|
+
withLeftIcon({ icon: 'general.x', accessibilityLabel: 'Close', onPress })
|
|
211
|
+
|
|
212
|
+
export const withRightDone = ({ onPress }: { onPress: () => void }) =>
|
|
213
|
+
withRightIcon({ icon: 'general.check', accessibilityLabel: 'Done', onPress })
|
|
91
214
|
|
|
92
|
-
|
|
93
|
-
// the button against the capsule edge.
|
|
94
|
-
export const createMinimalHeaderBackButton =
|
|
215
|
+
const createMinimalHeaderBackElement =
|
|
95
216
|
({ onPress }: { onPress: () => void }) =>
|
|
96
|
-
(props:
|
|
217
|
+
(props: NativeStackHeaderItemProps) => (
|
|
97
218
|
<HeaderBackButton
|
|
98
|
-
style={
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
marginLeft: Platform.select({ ios: -8, default: -3 }),
|
|
103
|
-
marginRight: Platform.select({ ios: 0, default: 30 }),
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
backImage={isLiquidGlassEnabled() ? renderGlassBackImage : undefined}
|
|
219
|
+
style={Platform.select({
|
|
220
|
+
ios: { marginLeft: -8 },
|
|
221
|
+
default: { marginLeft: -3, marginRight: 30 },
|
|
222
|
+
})}
|
|
107
223
|
displayMode="minimal"
|
|
108
224
|
onPress={onPress}
|
|
109
225
|
{...props}
|
|
110
226
|
/>
|
|
111
227
|
)
|
|
112
228
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
229
|
+
export const withMinimalBack =
|
|
230
|
+
({ onPress }: { onPress: () => void }): OptionsDecorator =>
|
|
231
|
+
options => ({
|
|
232
|
+
...options,
|
|
233
|
+
headerLeft: createMinimalHeaderBackElement({ onPress }),
|
|
234
|
+
unstable_headerLeftItems: () => [
|
|
235
|
+
createHeaderIconItem({ icon: 'general.leftChevron', accessibilityLabel: 'Back', onPress }),
|
|
236
|
+
],
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
type UseHeaderRightOptions = {
|
|
120
240
|
onPress: () => void
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
})
|
|
241
|
+
disabled?: boolean
|
|
242
|
+
enabled?: boolean
|
|
243
|
+
} & (
|
|
244
|
+
| (Omit<HeaderIconProps, 'tintColor'> & { title?: never })
|
|
245
|
+
| { title: string; icon?: never; accessibilityLabel?: never; prominent?: never }
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
export const useHeaderRight = (options: UseHeaderRightOptions) => {
|
|
249
|
+
const navigation = useNavigation()
|
|
250
|
+
const { colors } = useTheme()
|
|
251
|
+
const { onPress, disabled, enabled = true } = options
|
|
252
|
+
const icon = options.icon
|
|
253
|
+
const label = options.icon !== undefined ? options.accessibilityLabel : options.title
|
|
254
|
+
const prominent = options.icon !== undefined ? options.prominent : undefined
|
|
255
|
+
|
|
256
|
+
useLayoutEffect(() => {
|
|
257
|
+
if (!enabled) {
|
|
258
|
+
navigation.setOptions({ headerRight: () => null, unstable_headerRightItems: undefined })
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const decorate = icon
|
|
263
|
+
? withRightIcon({
|
|
264
|
+
icon,
|
|
265
|
+
accessibilityLabel: label,
|
|
266
|
+
onPress,
|
|
267
|
+
disabled,
|
|
268
|
+
prominent,
|
|
269
|
+
tintColor: prominent ? colors.interaction : undefined,
|
|
270
|
+
})
|
|
271
|
+
: withRightText({ text: label, onPress, disabled })
|
|
272
|
+
|
|
273
|
+
navigation.setOptions(decorate({}))
|
|
274
|
+
}, [colors.interaction, disabled, enabled, icon, label, navigation, onPress, prominent])
|
|
275
|
+
}
|
|
125
276
|
|
|
126
277
|
const useStyles = () => {
|
|
127
278
|
const { colors } = useTheme()
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from 'react-native'
|
|
13
13
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
14
14
|
import { useTheme } from '../../hooks'
|
|
15
|
-
import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
|
|
15
|
+
import { isLiquidGlassEnabled, MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
|
|
16
16
|
import type { ButtonProps, TextButtonProps } from '../display'
|
|
17
17
|
import { Button, Heading, Icon, IconString, Text, TextButton } from '../display'
|
|
18
18
|
|
|
@@ -22,24 +22,28 @@ import { Button, Heading, Icon, IconString, Text, TextButton } from '../display'
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Screen options for the formsheet's NativeStackNavigation route
|
|
25
|
+
*
|
|
26
|
+
* Returns a factory rather than an object because callers assign it at module
|
|
27
|
+
* scope, which runs before ChatProvider reports the host's liquid glass
|
|
28
|
+
* capability. React Navigation calls the factory per render, so the sheet
|
|
29
|
+
* corner radius is resolved once that capability is known.
|
|
30
|
+
*
|
|
25
31
|
* @param {string} options.headerTitle - Doesn't show in UI but good to have for semantic reasons.
|
|
26
32
|
* @param {number[]} [options.sheetAllowedDetents] - Controls the height increments the sheet grows to. To prevent bugs in Android, do not specify more then two values and use [0.94] instead of [1] to go full screen.
|
|
27
33
|
* @param {NativeStackNavigationOptions} [options.rest] - Adds or overrides any valid NativeStackNavigationOptions
|
|
28
|
-
* @returns {NativeStackNavigationOptions}
|
|
34
|
+
* @returns {() => NativeStackNavigationOptions} Factory producing merged NativeStackNavigationOptions
|
|
29
35
|
*/
|
|
30
|
-
export const getFormSheetScreenOptions =
|
|
31
|
-
headerTitle,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
...rest,
|
|
42
|
-
})
|
|
36
|
+
export const getFormSheetScreenOptions =
|
|
37
|
+
({ headerTitle, sheetAllowedDetents = [0.25], ...rest }: NativeStackNavigationOptions = {}) =>
|
|
38
|
+
(): NativeStackNavigationOptions => ({
|
|
39
|
+
presentation: 'formSheet',
|
|
40
|
+
headerShown: false,
|
|
41
|
+
sheetAllowedDetents,
|
|
42
|
+
sheetCornerRadius: isLiquidGlassEnabled() ? undefined : 16,
|
|
43
|
+
sheetGrabberVisible: true,
|
|
44
|
+
headerTitle,
|
|
45
|
+
...rest,
|
|
46
|
+
})
|
|
43
47
|
|
|
44
48
|
const FormSheet = {
|
|
45
49
|
Root: FormSheetRoot,
|