@planningcenter/chat-react-native 3.15.0-rc.0 → 3.15.0-rc.10

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 (204) hide show
  1. package/build/components/conversations/conversation_actions.js +1 -1
  2. package/build/components/conversations/conversation_actions.js.map +1 -1
  3. package/build/components/conversations/conversation_preview.d.ts.map +1 -1
  4. package/build/components/conversations/conversation_preview.js +9 -5
  5. package/build/components/conversations/conversation_preview.js.map +1 -1
  6. package/build/components/conversations/mute_indicator.d.ts.map +1 -1
  7. package/build/components/conversations/mute_indicator.js +3 -1
  8. package/build/components/conversations/mute_indicator.js.map +1 -1
  9. package/build/components/conversations/swipeable_toggle_button.d.ts.map +1 -1
  10. package/build/components/conversations/swipeable_toggle_button.js +6 -3
  11. package/build/components/conversations/swipeable_toggle_button.js.map +1 -1
  12. package/build/components/conversations/unread_count_badge.js +9 -6
  13. package/build/components/conversations/unread_count_badge.js.map +1 -1
  14. package/build/components/display/action_button.d.ts.map +1 -1
  15. package/build/components/display/action_button.js +2 -4
  16. package/build/components/display/action_button.js.map +1 -1
  17. package/build/components/display/avatar.d.ts +3 -1
  18. package/build/components/display/avatar.d.ts.map +1 -1
  19. package/build/components/display/avatar.js +2 -2
  20. package/build/components/display/avatar.js.map +1 -1
  21. package/build/components/display/avatar_group.d.ts +3 -1
  22. package/build/components/display/avatar_group.d.ts.map +1 -1
  23. package/build/components/display/avatar_group.js +2 -2
  24. package/build/components/display/avatar_group.js.map +1 -1
  25. package/build/components/display/badge.d.ts +5 -1
  26. package/build/components/display/badge.d.ts.map +1 -1
  27. package/build/components/display/badge.js +2 -2
  28. package/build/components/display/badge.js.map +1 -1
  29. package/build/components/display/icon.d.ts +26 -13
  30. package/build/components/display/icon.d.ts.map +1 -1
  31. package/build/components/display/icon.js +0 -12
  32. package/build/components/display/icon.js.map +1 -1
  33. package/build/components/display/index.d.ts +1 -0
  34. package/build/components/display/index.d.ts.map +1 -1
  35. package/build/components/display/index.js +1 -0
  36. package/build/components/display/index.js.map +1 -1
  37. package/build/components/display/pressable_row.d.ts +14 -0
  38. package/build/components/display/pressable_row.d.ts.map +1 -0
  39. package/build/components/display/pressable_row.js +65 -0
  40. package/build/components/display/pressable_row.js.map +1 -0
  41. package/build/components/display/toggle_button.d.ts +3 -1
  42. package/build/components/display/toggle_button.d.ts.map +1 -1
  43. package/build/components/display/toggle_button.js +1 -1
  44. package/build/components/display/toggle_button.js.map +1 -1
  45. package/build/components/primitive/avatar_primitive.d.ts +2 -0
  46. package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
  47. package/build/components/primitive/avatar_primitive.js +20 -19
  48. package/build/components/primitive/avatar_primitive.js.map +1 -1
  49. package/build/components/primitive/form_sheet.d.ts +3 -2
  50. package/build/components/primitive/form_sheet.d.ts.map +1 -1
  51. package/build/components/primitive/form_sheet.js +5 -3
  52. package/build/components/primitive/form_sheet.js.map +1 -1
  53. package/build/hooks/index.d.ts +1 -0
  54. package/build/hooks/index.d.ts.map +1 -1
  55. package/build/hooks/index.js +1 -0
  56. package/build/hooks/index.js.map +1 -1
  57. package/build/hooks/use_api.d.ts +1 -1
  58. package/build/hooks/use_api.d.ts.map +1 -1
  59. package/build/hooks/use_api.js.map +1 -1
  60. package/build/hooks/use_api_client.d.ts +1 -1
  61. package/build/hooks/use_api_client.d.ts.map +1 -1
  62. package/build/hooks/use_api_client.js +1 -1
  63. package/build/hooks/use_api_client.js.map +1 -1
  64. package/build/hooks/use_app_name.d.ts +3 -0
  65. package/build/hooks/use_app_name.d.ts.map +1 -0
  66. package/build/hooks/use_app_name.js +12 -0
  67. package/build/hooks/use_app_name.js.map +1 -0
  68. package/build/hooks/use_async_storage.d.ts +1 -1
  69. package/build/hooks/use_async_storage.d.ts.map +1 -1
  70. package/build/hooks/use_async_storage.js +6 -5
  71. package/build/hooks/use_async_storage.js.map +1 -1
  72. package/build/hooks/use_report_bug_action.d.ts +1 -1
  73. package/build/hooks/use_report_bug_action.d.ts.map +1 -1
  74. package/build/hooks/use_report_bug_action.js +1 -9
  75. package/build/hooks/use_report_bug_action.js.map +1 -1
  76. package/build/hooks/use_scalable_number_of_lines.d.ts +2 -0
  77. package/build/hooks/use_scalable_number_of_lines.d.ts.map +1 -0
  78. package/build/hooks/use_scalable_number_of_lines.js +9 -0
  79. package/build/hooks/use_scalable_number_of_lines.js.map +1 -0
  80. package/build/hooks/use_suspense_api.d.ts +1 -1
  81. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  82. package/build/hooks/use_suspense_api.js.map +1 -1
  83. package/build/index.d.ts +2 -0
  84. package/build/index.d.ts.map +1 -1
  85. package/build/index.js +2 -0
  86. package/build/index.js.map +1 -1
  87. package/build/navigation/index.d.ts +20 -5
  88. package/build/navigation/index.d.ts.map +1 -1
  89. package/build/navigation/index.js +23 -15
  90. package/build/navigation/index.js.map +1 -1
  91. package/build/polyfills/events/CustomEvent.d.ts +21 -0
  92. package/build/polyfills/events/CustomEvent.d.ts.map +1 -0
  93. package/build/polyfills/events/CustomEvent.js +22 -0
  94. package/build/polyfills/events/CustomEvent.js.map +1 -0
  95. package/build/polyfills/events/Event.d.ts +49 -0
  96. package/build/polyfills/events/Event.d.ts.map +1 -0
  97. package/build/polyfills/events/Event.js +125 -0
  98. package/build/polyfills/events/Event.js.map +1 -0
  99. package/build/polyfills/events/EventHandlerAttributes.d.ts +8 -0
  100. package/build/polyfills/events/EventHandlerAttributes.d.ts.map +1 -0
  101. package/build/polyfills/events/EventHandlerAttributes.js +46 -0
  102. package/build/polyfills/events/EventHandlerAttributes.js.map +1 -0
  103. package/build/polyfills/events/EventTarget.d.ts +33 -0
  104. package/build/polyfills/events/EventTarget.d.ts.map +1 -0
  105. package/build/polyfills/events/EventTarget.js +238 -0
  106. package/build/polyfills/events/EventTarget.js.map +1 -0
  107. package/build/polyfills/events/internals/EventInternals.d.ts +30 -0
  108. package/build/polyfills/events/internals/EventInternals.d.ts.map +1 -0
  109. package/build/polyfills/events/internals/EventInternals.js +76 -0
  110. package/build/polyfills/events/internals/EventInternals.js.map +1 -0
  111. package/build/polyfills/events/internals/EventTargetInternals.d.ts +9 -0
  112. package/build/polyfills/events/internals/EventTargetInternals.d.ts.map +1 -0
  113. package/build/polyfills/events/internals/EventTargetInternals.js +11 -0
  114. package/build/polyfills/events/internals/EventTargetInternals.js.map +1 -0
  115. package/build/polyfills/webidl/PlatformObjects.d.ts +31 -0
  116. package/build/polyfills/webidl/PlatformObjects.d.ts.map +1 -0
  117. package/build/polyfills/webidl/PlatformObjects.js +39 -0
  118. package/build/polyfills/webidl/PlatformObjects.js.map +1 -0
  119. package/build/screens/bug_report_screen.d.ts.map +1 -1
  120. package/build/screens/bug_report_screen.js +62 -57
  121. package/build/screens/bug_report_screen.js.map +1 -1
  122. package/build/screens/conversation_filters/components/conversation_filters.js +9 -7
  123. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  124. package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
  125. package/build/screens/conversation_filters/components/rows.js +50 -31
  126. package/build/screens/conversation_filters/components/rows.js.map +1 -1
  127. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
  128. package/build/screens/conversations/components/list_header_component.js +2 -2
  129. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  130. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  131. package/build/screens/conversations/conversations_screen.js +6 -6
  132. package/build/screens/conversations/conversations_screen.js.map +1 -1
  133. package/build/screens/design_system_screen.js +1 -1
  134. package/build/screens/design_system_screen.js.map +1 -1
  135. package/build/screens/get_help_screen.d.ts +5 -0
  136. package/build/screens/get_help_screen.d.ts.map +1 -0
  137. package/build/screens/get_help_screen.js +94 -0
  138. package/build/screens/get_help_screen.js.map +1 -0
  139. package/build/screens/message_actions_screen.d.ts +1 -1
  140. package/build/screens/message_actions_screen.d.ts.map +1 -1
  141. package/build/screens/message_actions_screen.js +14 -11
  142. package/build/screens/message_actions_screen.js.map +1 -1
  143. package/build/utils/client/index.d.ts +1 -0
  144. package/build/utils/client/index.d.ts.map +1 -1
  145. package/build/utils/client/index.js +1 -0
  146. package/build/utils/client/index.js.map +1 -1
  147. package/build/utils/client/types.d.ts +61 -0
  148. package/build/utils/client/types.d.ts.map +1 -0
  149. package/build/utils/client/types.js +2 -0
  150. package/build/utils/client/types.js.map +1 -0
  151. package/build/utils/styles.d.ts +1 -1
  152. package/build/utils/styles.js +1 -1
  153. package/build/utils/styles.js.map +1 -1
  154. package/build/utils/theme.d.ts +1 -0
  155. package/build/utils/theme.d.ts.map +1 -1
  156. package/build/utils/theme.js +2 -0
  157. package/build/utils/theme.js.map +1 -1
  158. package/package.json +5 -5
  159. package/src/__tests__/event-polyfill.test.ts +314 -0
  160. package/src/components/conversations/conversation_actions.tsx +1 -1
  161. package/src/components/conversations/conversation_preview.tsx +15 -4
  162. package/src/components/conversations/mute_indicator.tsx +9 -1
  163. package/src/components/conversations/swipeable_toggle_button.tsx +18 -3
  164. package/src/components/conversations/unread_count_badge.tsx +9 -6
  165. package/src/components/display/action_button.tsx +3 -4
  166. package/src/components/display/avatar.tsx +5 -1
  167. package/src/components/display/avatar_group.tsx +5 -1
  168. package/src/components/display/badge.tsx +6 -1
  169. package/src/components/display/icon.tsx +17 -14
  170. package/src/components/display/index.ts +1 -0
  171. package/src/components/display/pressable_row.tsx +103 -0
  172. package/src/components/display/toggle_button.tsx +12 -1
  173. package/src/components/primitive/avatar_primitive.tsx +35 -19
  174. package/src/components/primitive/form_sheet.tsx +33 -5
  175. package/src/hooks/index.ts +1 -0
  176. package/src/hooks/use_api.ts +1 -1
  177. package/src/hooks/use_api_client.ts +2 -2
  178. package/src/hooks/use_app_name.ts +17 -0
  179. package/src/hooks/use_async_storage.ts +8 -5
  180. package/src/hooks/use_report_bug_action.ts +2 -10
  181. package/src/hooks/use_scalable_number_of_lines.ts +10 -0
  182. package/src/hooks/use_suspense_api.ts +1 -1
  183. package/src/index.tsx +2 -0
  184. package/src/navigation/index.tsx +38 -25
  185. package/src/polyfills/events/CustomEvent.ts +32 -0
  186. package/src/polyfills/events/Event.ts +186 -0
  187. package/src/polyfills/events/EventHandlerAttributes.ts +67 -0
  188. package/src/polyfills/events/EventTarget.ts +360 -0
  189. package/src/polyfills/events/README.md +1 -0
  190. package/src/polyfills/events/internals/EventInternals.ts +95 -0
  191. package/src/polyfills/events/internals/EventTargetInternals.ts +16 -0
  192. package/src/polyfills/webidl/PlatformObjects.ts +50 -0
  193. package/src/screens/bug_report_screen.tsx +79 -67
  194. package/src/screens/conversation_filters/components/conversation_filters.tsx +10 -7
  195. package/src/screens/conversation_filters/components/rows.tsx +63 -50
  196. package/src/screens/conversations/components/list_header_component.tsx +3 -1
  197. package/src/screens/conversations/conversations_screen.tsx +8 -6
  198. package/src/screens/design_system_screen.tsx +1 -1
  199. package/src/screens/get_help_screen.tsx +131 -0
  200. package/src/screens/message_actions_screen.tsx +34 -12
  201. package/src/utils/client/index.ts +1 -0
  202. package/src/utils/styles.ts +1 -1
  203. package/src/utils/theme.ts +3 -0
  204. /package/src/utils/client/{types.d.ts → types.ts} +0 -0
@@ -0,0 +1,103 @@
1
+ import { PlatformPressable } from '@react-navigation/elements'
2
+ import { PropsWithChildren } from 'react'
3
+ import { StyleSheet, View, ViewStyle } from 'react-native'
4
+ import { useTheme } from '../../hooks'
5
+ import { Icon, IconProps } from './icon'
6
+ import { Text } from './text'
7
+
8
+ export interface PressableRowProps extends PropsWithChildren {
9
+ isActive?: boolean
10
+ onPress: () => void
11
+ style?: ViewStyle
12
+ textStyle?: any
13
+ text: string
14
+ iconPath?: IconProps['name']
15
+ iconColor?: string
16
+ }
17
+
18
+ export const PressableRow = ({
19
+ children,
20
+ isActive,
21
+ onPress,
22
+ style,
23
+ text,
24
+ textStyle,
25
+ iconPath,
26
+ iconColor,
27
+ }: PressableRowProps) => {
28
+ const styles = useRowStyles({ isActive, iconColor })
29
+
30
+ return (
31
+ <PlatformPressable
32
+ style={styles.container}
33
+ onPress={onPress}
34
+ accessibilityRole="radio"
35
+ accessibilityState={{ selected: isActive }}
36
+ >
37
+ <View style={[styles.innerContainer, style]}>
38
+ {children}
39
+ <Text style={textStyle}>{text}</Text>
40
+ <Icon
41
+ name={iconPath || 'general.check'}
42
+ size={16}
43
+ style={styles.rowIconRight}
44
+ accessibilityElementsHidden
45
+ />
46
+ </View>
47
+ </PlatformPressable>
48
+ )
49
+ }
50
+
51
+ const ASPECT_RATIO = 16 / 9
52
+ const THUMBNAIL_WIDTH = 80
53
+ const THUMBNAIL_HEIGHT = THUMBNAIL_WIDTH / ASPECT_RATIO
54
+
55
+ const useRowStyles = ({
56
+ isActive = false,
57
+ iconColor,
58
+ }: { isActive?: boolean; iconColor?: string } = {}) => {
59
+ const theme = useTheme()
60
+ return StyleSheet.create({
61
+ container: {
62
+ paddingLeft: 16,
63
+ },
64
+ innerContainer: {
65
+ flexDirection: 'row',
66
+ alignItems: 'center',
67
+ gap: 12,
68
+ borderBottomWidth: 1,
69
+ borderBottomColor: theme.colors.fillColorNeutral050Base,
70
+ paddingVertical: 12,
71
+ paddingRight: 16,
72
+ },
73
+ borderLessRow: {
74
+ flexDirection: 'row',
75
+ alignItems: 'center',
76
+ gap: 12,
77
+ paddingVertical: 12,
78
+ paddingRight: 16,
79
+ paddingLeft: 16,
80
+ },
81
+ viewMoreButton: {
82
+ flex: 1,
83
+ },
84
+ row: {},
85
+ rowImage: {
86
+ width: THUMBNAIL_WIDTH,
87
+ height: THUMBNAIL_HEIGHT,
88
+ borderRadius: 4,
89
+ },
90
+ rowContent: {
91
+ flexShrink: 1,
92
+ },
93
+ rowIconRight: {
94
+ marginLeft: 'auto',
95
+ color: iconColor || theme.colors.iconColorDefaultDim,
96
+ opacity: isActive ? 1 : 0,
97
+ },
98
+ rowTitle: {
99
+ fontSize: 16,
100
+ flexShrink: 1,
101
+ },
102
+ })
103
+ }
@@ -17,11 +17,20 @@ import { Icon, IconString } from './icon'
17
17
  import { tokens } from '../../vendor/tapestry/tokens'
18
18
  import { Haptic } from '../../utils/native_adapters/configuration'
19
19
 
20
+ // =================================
21
+ // ====== Constants ================
22
+ // =================================
23
+
24
+ // We are omitting `onLongPress` because we are instead supporting `accessibilityShowsLargeContentViewer`.
25
+ // This is triggered by an `onLongPress` event when an iOS device is in Apple's accessible font scale range.
26
+ // Triggering this prop will display an almost full screen iOS a11y button.
27
+ type RestrictedPressableProps = Omit<PressableProps, 'onLongPress'>
28
+
20
29
  // =================================
21
30
  // ====== Component ================
22
31
  // =================================
23
32
 
24
- export interface ToggleButtonProps extends PressableProps {
33
+ export interface ToggleButtonProps extends RestrictedPressableProps {
25
34
  /**
26
35
  * Pressable container styles
27
36
  */
@@ -102,6 +111,8 @@ export function ToggleButton({
102
111
  accessibilityState={{ checked: active }}
103
112
  android_ripple={{ color: androidRippleColor, borderless: false, foreground: true }}
104
113
  onPress={handlePress}
114
+ accessibilityShowsLargeContentViewer
115
+ accessibilityLargeContentTitle={title}
105
116
  {...props}
106
117
  >
107
118
  {iconNameLeft && (
@@ -85,6 +85,7 @@ interface AvatarContextType {
85
85
  size: AvatarSize
86
86
  allImagesLoaded: boolean
87
87
  setAllImagesLoaded: React.Dispatch<React.SetStateAction<boolean>>
88
+ maxFontSizeMultiplier: number
88
89
  }
89
90
 
90
91
  const AvatarContext = createContext<AvatarContextType | null>(null)
@@ -104,15 +105,24 @@ function useAvatarContext() {
104
105
  interface AvatarRootProps {
105
106
  children: React.ReactNode
106
107
  size?: AvatarSize
108
+ style?: ViewProps['style']
109
+ maxFontSizeMultiplier?: number
107
110
  }
108
111
 
109
- function AvatarRoot({ children, size = 'md' }: AvatarRootProps) {
112
+ function AvatarRoot({
113
+ children,
114
+ size = 'md',
115
+ style,
116
+ maxFontSizeMultiplier = MAX_FONT_SIZE_MULTIPLIER,
117
+ }: AvatarRootProps) {
110
118
  const [allImagesLoaded, setAllImagesLoaded] = useState(false)
111
- const styles = useStyles({ size })
119
+ const styles = useStyles({ size, maxFontSizeMultiplier })
112
120
 
113
121
  return (
114
- <AvatarContext.Provider value={{ size, allImagesLoaded, setAllImagesLoaded }}>
115
- <View style={styles.rootContainer}>{children}</View>
122
+ <AvatarContext.Provider
123
+ value={{ size, allImagesLoaded, setAllImagesLoaded, maxFontSizeMultiplier }}
124
+ >
125
+ <View style={[styles.rootContainer, style]}>{children}</View>
116
126
  </AvatarContext.Provider>
117
127
  )
118
128
  }
@@ -126,7 +136,8 @@ AvatarRoot.displayName = 'Avatar.Root'
126
136
  type AvatarMaskProps = ViewProps
127
137
 
128
138
  function AvatarMask({ children, ...props }: AvatarMaskProps) {
129
- const styles = useStyles()
139
+ const { maxFontSizeMultiplier } = useAvatarContext()
140
+ const styles = useStyles({ maxFontSizeMultiplier })
130
141
 
131
142
  return (
132
143
  <View style={styles.mask} {...props}>
@@ -146,8 +157,8 @@ interface AvatarImageProps extends Omit<ImageProps, 'source' | 'alt'> {
146
157
  }
147
158
 
148
159
  function AvatarImage({ sourceUri, ...props }: AvatarImageProps) {
149
- const { size } = useAvatarContext()
150
- const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
160
+ const { size, maxFontSizeMultiplier } = useAvatarContext()
161
+ const fontScale = useFontScale({ maxFontSizeMultiplier })
151
162
  const scaledAvatarSize = AVATAR_PX[size] * fontScale
152
163
 
153
164
  return <Image source={{ uri: sourceUri }} loaderSize={scaledAvatarSize} {...props} alt="" />
@@ -172,9 +183,9 @@ interface AvatarImageFallbackProps {
172
183
  }
173
184
 
174
185
  function AvatarImageFallback({ name = 'general.person' }: AvatarImageFallbackProps) {
175
- const { size } = useAvatarContext()
176
- const styles = useStyles()
177
- const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
186
+ const { size, maxFontSizeMultiplier } = useAvatarContext()
187
+ const styles = useStyles({ maxFontSizeMultiplier })
188
+ const fontScale = useFontScale({ maxFontSizeMultiplier })
178
189
  const scaledIconSize = AVATAR_FALLBACK_ICON_PX[size] * fontScale
179
190
 
180
191
  return (
@@ -202,8 +213,8 @@ interface AvatarGroupProps {
202
213
  type AvatarIndex = 0 | 1 | 2 | 3
203
214
 
204
215
  function AvatarGroup({ sourceUris }: AvatarGroupProps) {
205
- const styles = useStyles()
206
- const { setAllImagesLoaded } = useAvatarContext()
216
+ const { setAllImagesLoaded, maxFontSizeMultiplier } = useAvatarContext()
217
+ const styles = useStyles({ maxFontSizeMultiplier })
207
218
  const [loadingStatus, setLoadingStatus] = useState<Record<AvatarIndex, boolean>>({
208
219
  0: false,
209
220
  1: false,
@@ -312,9 +323,9 @@ AvatarGroup.displayName = 'Avatar.Group'
312
323
  // =================================
313
324
 
314
325
  function AvatarGroupLoader() {
315
- const { size, allImagesLoaded } = useAvatarContext()
316
- const styles = useStyles({ size })
317
- const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
326
+ const { size, allImagesLoaded, maxFontSizeMultiplier } = useAvatarContext()
327
+ const styles = useStyles({ size, maxFontSizeMultiplier })
328
+ const fontScale = useFontScale({ maxFontSizeMultiplier })
318
329
  const scaledSpinnerSize = AVATAR_PX[size] * fontScale
319
330
 
320
331
  if (allImagesLoaded) return null
@@ -337,8 +348,8 @@ interface AvatarPresenceProps extends ViewProps {
337
348
  }
338
349
 
339
350
  function AvatarPresence({ presence, ...props }: AvatarPresenceProps) {
340
- const { size } = useAvatarContext()
341
- const styles = useStyles({ size, presence })
351
+ const { size, maxFontSizeMultiplier } = useAvatarContext()
352
+ const styles = useStyles({ size, presence, maxFontSizeMultiplier })
342
353
 
343
354
  return <View style={styles.presence} {...props} />
344
355
  }
@@ -352,11 +363,16 @@ AvatarPresence.displayName = 'Avatar.Presence'
352
363
  interface Styles {
353
364
  size?: AvatarSize
354
365
  presence?: AvatarPresenceType
366
+ maxFontSizeMultiplier?: number
355
367
  }
356
368
 
357
- const useStyles = ({ size = 'md', presence = 'offline' }: Styles = {}) => {
369
+ const useStyles = ({
370
+ size = 'md',
371
+ presence = 'offline',
372
+ maxFontSizeMultiplier = MAX_FONT_SIZE_MULTIPLIER,
373
+ }: Styles = {}) => {
358
374
  const { colors } = useTheme()
359
- const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
375
+ const fontScale = useFontScale({ maxFontSizeMultiplier })
360
376
  const PRESENCE_COLOR = {
361
377
  online: colors.fillColorInteractionOnlineDefault,
362
378
  offline: colors.iconColorDefaultDisabled,
@@ -14,6 +14,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
14
14
  import { useTheme } from '../../hooks'
15
15
  import type { ButtonProps, TextButtonProps } from '../display'
16
16
  import { Button, Heading, Icon, IconString, Text, TextButton } from '../display'
17
+ import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
17
18
 
18
19
  // =================================
19
20
  // ====== Exports ==================
@@ -146,7 +147,11 @@ function FormSheetHeaderTitle({ children }: FormSheetHeaderTitleProps) {
146
147
  const styles = useStyles()
147
148
 
148
149
  return (
149
- <Heading variant="h3" style={styles.headerTitle} maxFontSizeMultiplier={1}>
150
+ <Heading
151
+ variant="h3"
152
+ style={styles.headerTitle}
153
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
154
+ >
150
155
  {children}
151
156
  </Heading>
152
157
  )
@@ -174,10 +179,23 @@ FormSheetHeaderActions.displayName = 'FormSheet.HeaderActions'
174
179
  // ====== FormSheetHeaderTextButton ==========
175
180
  // ===========================================
176
181
 
177
- interface FormSheetHeaderTextButtonProps extends Omit<TextButtonProps, 'maxFontSizeMultiplier'> {}
182
+ // We are omitting `onLongPress` because we are instead supporting `accessibilityShowsLargeContentViewer`.
183
+ // This is triggered by an `onLongPress` event when an iOS device is in Apple's accessible font scale range.
184
+ // Triggering this prop will display an almost full screen iOS a11y button.
185
+ interface FormSheetHeaderTextButtonProps
186
+ extends Omit<TextButtonProps, 'maxFontSizeMultiplier' | 'onLongPress'> {
187
+ children: string
188
+ }
178
189
 
179
190
  function FormSheetHeaderTextButton(props: FormSheetHeaderTextButtonProps) {
180
- return <TextButton {...props} maxFontSizeMultiplier={1} />
191
+ return (
192
+ <TextButton
193
+ {...props}
194
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
195
+ accessibilityShowsLargeContentViewer
196
+ accessibilityLargeContentTitle={props.children}
197
+ />
198
+ )
181
199
  }
182
200
 
183
201
  FormSheetHeaderTextButton.displayName = 'FormSheet.HeaderTextButton'
@@ -186,10 +204,19 @@ FormSheetHeaderTextButton.displayName = 'FormSheet.HeaderTextButton'
186
204
  // ====== FormSheetHeaderButton ============
187
205
  // =========================================
188
206
 
189
- interface FormSheetHeaderButtonProps extends Omit<ButtonProps, 'maxFontSizeMultiplier'> {}
207
+ // Same `onLongPress`note as `FormSheetHeaderTextButtonProps`
208
+ interface FormSheetHeaderButtonProps
209
+ extends Omit<ButtonProps, 'maxFontSizeMultiplier' | 'onLongPress'> {}
190
210
 
191
211
  function FormSheetHeaderButton(props: FormSheetHeaderButtonProps) {
192
- return <Button {...props} maxFontSizeMultiplier={1} />
212
+ return (
213
+ <Button
214
+ {...props}
215
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
216
+ accessibilityShowsLargeContentViewer
217
+ accessibilityLargeContentTitle={props.title}
218
+ />
219
+ )
193
220
  }
194
221
 
195
222
  FormSheetHeaderButton.displayName = 'FormSheet.HeaderButton'
@@ -324,6 +351,7 @@ const useStyles = ({ appearance = 'neutral' }: Styles = {}) => {
324
351
  },
325
352
  headerTitle: {
326
353
  textAlign: 'left',
354
+ flex: 1,
327
355
  },
328
356
  headerActions: {
329
357
  flexDirection: 'row',
@@ -13,3 +13,4 @@ export * from './use_api_client'
13
13
  export * from './use_message_reaction_toggle'
14
14
  export * from './use_interaction_ghost_color'
15
15
  export * from './use_at_font_scale_breakpoint'
16
+ export * from './use_scalable_number_of_lines'
@@ -5,7 +5,7 @@ import {
5
5
  useQuery,
6
6
  } from '@tanstack/react-query'
7
7
  import { ApiCollection, ApiError, ApiResource, ResourceObject } from '../types'
8
- import { GetRequest, RequestData } from '../utils/client/types'
8
+ import { GetRequest, RequestData } from '../utils/client'
9
9
  import { App, useApiClient } from './use_api_client'
10
10
  import { getRequestQueryKey, RequestQueryKey } from './use_suspense_api'
11
11
 
@@ -3,8 +3,8 @@ import { ChatContext } from '../contexts/chat_context'
3
3
  import { Client } from '../utils/client'
4
4
  import { Uri } from '../utils'
5
5
 
6
- export type App = 'chat' | 'groups' | 'services'
7
- const apps: App[] = ['chat', 'groups', 'services']
6
+ export type App = 'chat' | 'groups' | 'services' | 'people'
7
+ const apps: App[] = ['chat', 'groups', 'services', 'people']
8
8
 
9
9
  export type ApiClient = { [_K in App]: Client }
10
10
 
@@ -0,0 +1,17 @@
1
+ import DeviceInfo from 'react-native-device-info'
2
+
3
+ export type AppName = 'chat' | 'churchcenter' | 'services'
4
+
5
+ export const useAppName = (): AppName => {
6
+ const applicationName = DeviceInfo.getApplicationName()
7
+
8
+ if (/churchcenter/i.test(applicationName)) {
9
+ return 'churchcenter'
10
+ }
11
+
12
+ if (/services/i.test(applicationName)) {
13
+ return 'services'
14
+ }
15
+
16
+ return 'chat'
17
+ }
@@ -4,7 +4,7 @@ import { useCallback } from 'react'
4
4
 
5
5
  const cacheKeyGenerator = (key: string) => [`AsyncStorageResource:${key}`]
6
6
 
7
- type SetValue<TCacheData> = (_itemValue?: TCacheData | null) => void
7
+ type SetValue<TCacheData> = (_itemValue?: TCacheData | null) => Promise<void>
8
8
 
9
9
  export function useAsyncStorage<TCacheData>(
10
10
  key: string,
@@ -28,11 +28,14 @@ export function useAsyncStorage<TCacheData>(
28
28
  const setValue: SetValue<TCacheData> = useCallback(
29
29
  itemValue => {
30
30
  if (itemValue === null || itemValue === undefined) {
31
- AsyncStorage.removeItem(key)
32
- } else {
33
- AsyncStorage.setItem(key, JSON.stringify(itemValue))
31
+ return AsyncStorage.removeItem(key).then(() => {
32
+ refetch()
33
+ })
34
34
  }
35
- refetch()
35
+
36
+ return AsyncStorage.setItem(key, JSON.stringify(itemValue)).then(() => {
37
+ refetch()
38
+ })
36
39
  },
37
40
  [key, refetch]
38
41
  )
@@ -1,12 +1,5 @@
1
1
  import { useMutation } from '@tanstack/react-query'
2
2
  import { useApiClient } from './use_api_client'
3
- import DeviceInfo from 'react-native-device-info'
4
- const brand = DeviceInfo.getBrand()
5
- const model = DeviceInfo.getModel()
6
- const systemName = DeviceInfo.getSystemName()
7
- const systemVersion = DeviceInfo.getSystemVersion()
8
- const readableVersion = DeviceInfo.getReadableVersion()
9
- const appName = DeviceInfo.getApplicationName()
10
3
 
11
4
  export const useReportBugAction = () => {
12
5
  const apiClient = useApiClient()
@@ -18,7 +11,7 @@ export const useReportBugAction = () => {
18
11
  attachmentIds,
19
12
  }: {
20
13
  description: string
21
- description_json: string
14
+ description_json: Record<string, any>
22
15
  attachmentIds: string[]
23
16
  }) => {
24
17
  return apiClient.chat.post({
@@ -28,8 +21,7 @@ export const useReportBugAction = () => {
28
21
  type: '',
29
22
  attributes: {
30
23
  description,
31
- description_json,
32
- device_info: `${appName}/${readableVersion} (${brand}, ${model}, ${systemName}, ${systemVersion})`,
24
+ description_json: JSON.stringify(description_json),
33
25
  attachment_ids: attachmentIds,
34
26
  },
35
27
  },
@@ -0,0 +1,10 @@
1
+ import { useAtFontScaleBreakpoint } from './use_at_font_scale_breakpoint'
2
+
3
+ export const useScalableNumberOfLines = (numberOfLines?: number): number | undefined => {
4
+ const atFontScaleBreakpoint = useAtFontScaleBreakpoint()
5
+
6
+ if (!numberOfLines) return undefined
7
+
8
+ const numberOfLinesDoubled = numberOfLines + 1
9
+ return atFontScaleBreakpoint ? numberOfLinesDoubled : numberOfLines
10
+ }
@@ -6,7 +6,7 @@ import {
6
6
  UseSuspenseQueryOptions,
7
7
  } from '@tanstack/react-query'
8
8
  import { ApiCollection, ApiResource, ResourceObject } from '../types'
9
- import { GetRequest, RequestData } from '../utils/client/types'
9
+ import { GetRequest, RequestData } from '../utils/client'
10
10
  import { App, useApiClient } from './use_api_client'
11
11
  import { Log } from '../utils'
12
12
  import { ApiError } from '../types/api_primitives'
package/src/index.tsx CHANGED
@@ -8,3 +8,5 @@ export * from './types'
8
8
  export { platformFontWeightBold, Session, TemporaryDefaultColorsType, Uri } from './utils'
9
9
  export * from './utils/client'
10
10
  export * from './utils/native_adapters'
11
+ export { default as Event } from './polyfills/events/Event'
12
+ export { CustomEvent } from './polyfills/events/CustomEvent'
@@ -4,47 +4,50 @@ import {
4
4
  createNativeStackNavigator,
5
5
  NativeStackHeaderRightProps,
6
6
  } from '@react-navigation/native-stack'
7
+ import { CardStyleInterpolators } from '@react-navigation/stack'
7
8
  import React from 'react'
9
+ import { Platform } from 'react-native'
8
10
  import { Icon } from '../components'
11
+ import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
12
+ import {
13
+ AttachmentActionsScreen,
14
+ AttachmentActionsScreenOptions,
15
+ } from '../screens/attachment_actions/attachment_actions_screen'
16
+ import { BugReportScreen, BugReportScreenOptions } from '../screens/bug_report_screen'
17
+ import {
18
+ MessageReadReceiptsScreen,
19
+ MessageReadReceiptsScreenOptions,
20
+ } from '../screens/conversation/message_read_receipts_screen'
9
21
  import { ConversationDetailsScreen } from '../screens/conversation_details_screen'
22
+ import {
23
+ ConversationFilterReceipientsScreenOptions,
24
+ ConversationFilterRecipientsScreen,
25
+ } from '../screens/conversation_filter_recipients/conversation_filter_recipients_screen'
26
+ import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
27
+ import {
28
+ ConversationFiltersScreen,
29
+ ConversationFiltersScreenOptions,
30
+ } from '../screens/conversation_filters_screen'
31
+ import { ConversationNewScreen } from '../screens/conversation_new/conversation_new_screen'
10
32
  import {
11
33
  ConversationRouteProps,
12
34
  ConversationScreen,
13
35
  ConversationScreenTitle,
14
36
  } from '../screens/conversation_screen'
15
- import { ConversationsScreen } from '../screens/conversations/conversations_screen'
16
- import { ConversationNewScreen } from '../screens/conversation_new/conversation_new_screen'
17
- import {
18
- ConversationFilterReceipientsScreenOptions,
19
- ConversationFilterRecipientsScreen,
20
- } from '../screens/conversation_filter_recipients/conversation_filter_recipients_screen'
37
+ import { ConversationSelectGroupRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_group_recipients_screen'
21
38
  import { ConversationSelectRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_recipients_screen'
39
+ import { ConversationSelectTeamsILeadRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
40
+ import { ConversationsScreen } from '../screens/conversations/conversations_screen'
41
+ import { GetHelpScreen } from '../screens/get_help_screen'
22
42
  import {
23
43
  MessageActionsScreen,
24
44
  MessageActionsScreenOptions,
25
45
  } from '../screens/message_actions_screen'
26
- import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
27
46
  import { NotFound } from '../screens/not_found'
28
47
  import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'
29
- import { ScreenLayout } from './screenLayout'
30
- import {
31
- ConversationFiltersScreen,
32
- ConversationFiltersScreenOptions,
33
- } from '../screens/conversation_filters_screen'
34
- import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
35
- import { ConversationSelectGroupRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_group_recipients_screen'
36
- import { ConversationSelectTeamsILeadRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
37
- import { AttachmentActionsScreenOptions } from '../screens/attachment_actions/attachment_actions_screen'
38
- import { AttachmentActionsScreen } from '../screens/attachment_actions/attachment_actions_screen'
39
- import { BugReportScreen, BugReportScreenOptions } from '../screens/bug_report_screen'
40
- import {
41
- MessageReadReceiptsScreen,
42
- MessageReadReceiptsScreenOptions,
43
- } from '../screens/conversation/message_read_receipts_screen'
44
- import { Platform } from 'react-native'
45
- import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
48
+ import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
46
49
  import { TeamConversationScreen } from '../screens/team_conversation_screen'
47
- import { CardStyleInterpolators } from '@react-navigation/stack'
50
+ import { ScreenLayout } from './screenLayout'
48
51
 
49
52
  const HEADER_BACK_BUTTON_LAYOUT_RESET_STYLES = {
50
53
  marginLeft: Platform.select({ ios: -8, default: -3 }),
@@ -231,6 +234,16 @@ export const ChatStack = createNativeStackNavigator({
231
234
  screen: BugReportScreen,
232
235
  options: BugReportScreenOptions,
233
236
  },
237
+ GetHelp: {
238
+ screen: GetHelpScreen,
239
+ options: ({ navigation }) => ({
240
+ headerTitle: 'Get help',
241
+ presentation: 'modal',
242
+ headerLeft: props => (
243
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Close" />
244
+ ),
245
+ }),
246
+ },
234
247
  NotFound: {
235
248
  screen: NotFound,
236
249
  options: {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /**
9
+ * This module implements the `CustomEvent` interface from the DOM.
10
+ * See https://dom.spec.whatwg.org/#interface-customevent.
11
+ */
12
+
13
+ import Event from './Event'
14
+ import type { EventInit as RNEventInit } from './Event'
15
+
16
+ export interface CustomEventInit extends RNEventInit {
17
+ detail?: unknown
18
+ }
19
+
20
+ export class CustomEvent extends Event {
21
+ private _detail: unknown
22
+
23
+ constructor(type: string, options?: CustomEventInit) {
24
+ super(type, options)
25
+
26
+ this._detail = options?.detail
27
+ }
28
+
29
+ get detail(): unknown {
30
+ return this._detail
31
+ }
32
+ }