@planningcenter/chat-react-native 3.14.0-rc.4 → 3.14.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 (105) hide show
  1. package/build/components/conversation/empty_conversation_blank_state.d.ts.map +1 -1
  2. package/build/components/conversation/empty_conversation_blank_state.js +10 -2
  3. package/build/components/conversation/empty_conversation_blank_state.js.map +1 -1
  4. package/build/components/conversations/conversations.d.ts.map +1 -1
  5. package/build/components/conversations/conversations.js +7 -2
  6. package/build/components/conversations/conversations.js.map +1 -1
  7. package/build/components/display/action_button.d.ts.map +1 -1
  8. package/build/components/display/action_button.js +2 -1
  9. package/build/components/display/action_button.js.map +1 -1
  10. package/build/components/display/badge.js +5 -5
  11. package/build/components/display/badge.js.map +1 -1
  12. package/build/components/display/index.d.ts +0 -1
  13. package/build/components/display/index.d.ts.map +1 -1
  14. package/build/components/display/index.js +0 -1
  15. package/build/components/display/index.js.map +1 -1
  16. package/build/components/display/platform_modal_header_buttons.d.ts +4 -4
  17. package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -1
  18. package/build/components/display/platform_modal_header_buttons.js +2 -2
  19. package/build/components/display/platform_modal_header_buttons.js.map +1 -1
  20. package/build/components/display/text.d.ts +10 -2
  21. package/build/components/display/text.d.ts.map +1 -1
  22. package/build/components/display/text.js +0 -3
  23. package/build/components/display/text.js.map +1 -1
  24. package/build/components/display/toggle_button.d.ts.map +1 -1
  25. package/build/components/display/toggle_button.js +2 -2
  26. package/build/components/display/toggle_button.js.map +1 -1
  27. package/build/components/page/error_boundary.d.ts.map +1 -1
  28. package/build/components/page/error_boundary.js +11 -46
  29. package/build/components/page/error_boundary.js.map +1 -1
  30. package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
  31. package/build/components/primitive/avatar_primitive.js +14 -6
  32. package/build/components/primitive/avatar_primitive.js.map +1 -1
  33. package/build/components/primitive/blank_state_primitive.d.ts +41 -0
  34. package/build/components/primitive/blank_state_primitive.d.ts.map +1 -0
  35. package/build/components/primitive/blank_state_primitive.js +93 -0
  36. package/build/components/primitive/blank_state_primitive.js.map +1 -0
  37. package/build/navigation/index.d.ts.map +1 -1
  38. package/build/navigation/index.js +6 -6
  39. package/build/navigation/index.js.map +1 -1
  40. package/build/screens/bug_report_screen.d.ts.map +1 -1
  41. package/build/screens/bug_report_screen.js +17 -11
  42. package/build/screens/bug_report_screen.js.map +1 -1
  43. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  44. package/build/screens/conversation_details_screen.js +3 -3
  45. package/build/screens/conversation_details_screen.js.map +1 -1
  46. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts.map +1 -1
  47. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js +8 -2
  48. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js.map +1 -1
  49. package/build/screens/conversation_new/components/filter_by_plan.js +2 -2
  50. package/build/screens/conversation_new/components/filter_by_plan.js.map +1 -1
  51. package/build/screens/conversation_screen.d.ts.map +1 -1
  52. package/build/screens/conversation_screen.js +8 -7
  53. package/build/screens/conversation_screen.js.map +1 -1
  54. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts.map +1 -1
  55. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js +13 -3
  56. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js.map +1 -1
  57. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
  58. package/build/screens/conversations/components/list_header_component.js +2 -1
  59. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  60. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  61. package/build/screens/conversations/conversations_screen.js +2 -2
  62. package/build/screens/conversations/conversations_screen.js.map +1 -1
  63. package/build/screens/design_system_screen.js +13 -8
  64. package/build/screens/design_system_screen.js.map +1 -1
  65. package/build/screens/send_giphy_screen.d.ts.map +1 -1
  66. package/build/screens/send_giphy_screen.js +10 -5
  67. package/build/screens/send_giphy_screen.js.map +1 -1
  68. package/build/utils/styles.d.ts +1 -0
  69. package/build/utils/styles.d.ts.map +1 -1
  70. package/build/utils/styles.js +1 -0
  71. package/build/utils/styles.js.map +1 -1
  72. package/package.json +2 -2
  73. package/src/components/conversation/empty_conversation_blank_state.tsx +10 -6
  74. package/src/components/conversations/conversations.tsx +7 -2
  75. package/src/components/display/action_button.tsx +2 -0
  76. package/src/components/display/badge.tsx +5 -5
  77. package/src/components/display/index.ts +0 -1
  78. package/src/components/display/platform_modal_header_buttons.tsx +6 -6
  79. package/src/components/display/text.tsx +30 -2
  80. package/src/components/display/toggle_button.tsx +6 -2
  81. package/src/components/page/error_boundary.tsx +16 -47
  82. package/src/components/primitive/avatar_primitive.tsx +14 -6
  83. package/src/components/primitive/blank_state_primitive.tsx +211 -0
  84. package/src/navigation/index.tsx +6 -6
  85. package/src/screens/bug_report_screen.tsx +22 -20
  86. package/src/screens/conversation_details_screen.tsx +13 -4
  87. package/src/screens/conversation_filter_recipients/conversation_filter_recipients_screen.tsx +11 -2
  88. package/src/screens/conversation_new/components/filter_by_plan.tsx +2 -2
  89. package/src/screens/conversation_screen.tsx +13 -11
  90. package/src/screens/conversation_select_recipients/conversation_select_recipients_screen.tsx +17 -6
  91. package/src/screens/conversations/components/list_header_component.tsx +6 -1
  92. package/src/screens/conversations/conversations_screen.tsx +6 -2
  93. package/src/screens/design_system_screen.tsx +17 -13
  94. package/src/screens/send_giphy_screen.tsx +10 -11
  95. package/src/utils/styles.ts +1 -0
  96. package/build/components/display/blank_state.d.ts +0 -18
  97. package/build/components/display/blank_state.d.ts.map +0 -1
  98. package/build/components/display/blank_state.js +0 -47
  99. package/build/components/display/blank_state.js.map +0 -1
  100. package/build/navigation/header.d.ts +0 -10
  101. package/build/navigation/header.d.ts.map +0 -1
  102. package/build/navigation/header.js +0 -16
  103. package/build/navigation/header.js.map +0 -1
  104. package/src/components/display/blank_state.tsx +0 -76
  105. package/src/navigation/header.tsx +0 -24
@@ -1,11 +1,15 @@
1
- import { BlankState } from '../display'
1
+ import BlankState from '../primitive/blank_state_primitive'
2
2
 
3
3
  export const EmptyConversationBlankState = () => {
4
4
  return (
5
- <BlankState
6
- iconName="general.outlinedTextMessage"
7
- title="No messages"
8
- subtitle="Conversation is hidden from everyone until you send a message."
9
- />
5
+ <BlankState.Root>
6
+ <BlankState.Imagery name="general.outlinedTextMessage" />
7
+ <BlankState.Content>
8
+ <BlankState.Heading>No messages</BlankState.Heading>
9
+ <BlankState.Text>
10
+ Conversation is hidden from everyone until you send a message.
11
+ </BlankState.Text>
12
+ </BlankState.Content>
13
+ </BlankState.Root>
10
14
  )
11
15
  }
@@ -6,7 +6,7 @@ import { useConversationsContext } from '../../contexts/conversations_context'
6
6
  import { useTheme } from '../../hooks'
7
7
  import { ConversationResource } from '../../types'
8
8
  import { throwResponseError } from '../../utils/response_error'
9
- import { BlankState } from '../display'
9
+ import BlankState from '../primitive/blank_state_primitive'
10
10
  import { ConversationPreview, ConversationPreviewSkeleton } from './conversation_preview'
11
11
  import { useConversationsJoltEvents } from '../../hooks/use_conversations_jolt_events'
12
12
 
@@ -64,7 +64,12 @@ export const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {
64
64
  ListHeaderComponent={ListHeaderComponent}
65
65
  ListEmptyComponent={
66
66
  <View style={styles.listEmpty}>
67
- <BlankState iconName="general.outlinedTextMessage" title="No conversations" />
67
+ <BlankState.Root>
68
+ <BlankState.Imagery name="general.outlinedTextMessage" />
69
+ <BlankState.Content>
70
+ <BlankState.Heading>No conversations</BlankState.Heading>
71
+ </BlankState.Content>
72
+ </BlankState.Root>
68
73
  </View>
69
74
  }
70
75
  renderItem={({ item }) => {
@@ -6,6 +6,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'
6
6
  import { useTheme } from '../../hooks'
7
7
  import { Text } from './text'
8
8
  import { IconString } from './icon'
9
+ import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../utils'
9
10
 
10
11
  export const ActionButton = ({
11
12
  visible = true,
@@ -56,6 +57,7 @@ export const ActionButton = ({
56
57
  style={secondaryButton ? null : styles.fullWidthButton}
57
58
  iconNameLeft={buttonIconNameLeft}
58
59
  loading={loading}
60
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
59
61
  />
60
62
  </View>
61
63
  </Animated.View>
@@ -175,9 +175,9 @@ const useStyles = ({
175
175
 
176
176
  const statusColorMap = useStatusColorAppearanceMap()
177
177
 
178
- const badgePaddingHorizontal = 8 * fontScale
179
- const badgePaddingVertical = 4 * fontScale
180
178
  const badgeGap = 4 * fontScale
179
+ const badgePaddingHorizontal = 8
180
+ const badgePaddingVertical = 4
181
181
  const badgeFontSize = 12
182
182
 
183
183
  const variantStylesMap: VariantStyles = {
@@ -188,7 +188,7 @@ const useStyles = ({
188
188
  paddingHorizontal: badgePaddingHorizontal,
189
189
  paddingVertical: badgePaddingVertical,
190
190
  borderWidth: tokens.borderSizeDefault * fontScale,
191
- borderRadius: tokens.borderRadiusMd,
191
+ borderRadius: tokens.borderRadiusMd * fontScale,
192
192
  textColor: statusColorMap[appearance].text,
193
193
  fontWeight: 'normal',
194
194
  },
@@ -199,7 +199,7 @@ const useStyles = ({
199
199
  paddingHorizontal: badgePaddingHorizontal,
200
200
  paddingVertical: badgePaddingVertical,
201
201
  borderWidth: tokens.borderSizeDefault * fontScale,
202
- borderRadius: tokens.borderRadiusMd,
202
+ borderRadius: tokens.borderRadiusMd * fontScale,
203
203
  textColor: statusColorMap[appearance].text,
204
204
  fontWeight: platformFontWeightMedium,
205
205
  },
@@ -219,7 +219,6 @@ const useStyles = ({
219
219
  return StyleSheet.create({
220
220
  badgeWrapper: {
221
221
  flexDirection: 'row',
222
- alignItems: 'center',
223
222
  justifyContent: 'center',
224
223
  alignSelf: 'flex-start',
225
224
  borderRadius: variantStylesMap[variant].borderRadius,
@@ -255,6 +254,7 @@ const useStyles = ({
255
254
  metaLabel: {
256
255
  paddingHorizontal: variantStylesMap[variant].paddingHorizontal,
257
256
  fontSize: badgeFontSize,
257
+ alignSelf: 'center',
258
258
  flexShrink: 1,
259
259
  paddingLeft: variantStylesMap[variant].metaLabelPaddingLeft,
260
260
  },
@@ -3,7 +3,6 @@ export * from './avatar'
3
3
  export * from './badge'
4
4
  export * from './banner_collapsible'
5
5
  export * from './banner'
6
- export * from './blank_state'
7
6
  export * from './button'
8
7
  export * from './child_notice'
9
8
  export * from './heading'
@@ -4,17 +4,17 @@ import { HeaderButton } from '@react-navigation/elements'
4
4
  import { Icon } from './icon'
5
5
  import { useTheme } from '../../hooks'
6
6
 
7
- interface HeaderSubmitButtonProps {
7
+ interface HeaderTextButtonProps {
8
8
  onPress: () => void
9
9
  title?: string
10
10
  disabled?: boolean
11
11
  }
12
12
 
13
- export const HeaderSubmitButton = ({
13
+ export const HeaderTextButton = ({
14
14
  onPress,
15
15
  title = 'Submit',
16
16
  ...props
17
- }: HeaderSubmitButtonProps) => {
17
+ }: HeaderTextButtonProps) => {
18
18
  const styles = useStyles()
19
19
 
20
20
  return (
@@ -29,18 +29,18 @@ export const HeaderSubmitButton = ({
29
29
  )
30
30
  }
31
31
 
32
- interface HeaderCancelButtonProps {
32
+ interface HeaderDismissButtonProps {
33
33
  onPress: () => void
34
34
  title?: string
35
35
  tintColor?: ColorValue
36
36
  }
37
37
 
38
- export const HeaderCancelButton = ({
38
+ export const HeaderDismissButton = ({
39
39
  onPress,
40
40
  title = 'Cancel',
41
41
  tintColor,
42
42
  ...props
43
- }: HeaderCancelButtonProps) => {
43
+ }: HeaderDismissButtonProps) => {
44
44
  const styles = useStyles()
45
45
 
46
46
  return Platform.select({
@@ -1,13 +1,37 @@
1
1
  import { useTheme } from '../../hooks'
2
2
  import React from 'react'
3
3
  import { StyleSheet, Text as ReactNativeText, Platform } from 'react-native'
4
- import type { TextStyle, TextProps as ReactNativeTextProps } from 'react-native'
4
+ import type {
5
+ TextStyle as ReactNativeTextStyle,
6
+ TextProps as ReactNativeTextProps,
7
+ StyleProp,
8
+ } from 'react-native'
5
9
  import { tokens } from '../../vendor/tapestry/tokens'
6
10
 
7
11
  // =================================
8
12
  // ====== Constants ================
9
13
  // =================================
10
14
 
15
+ // TextStyle extends ViewStyle, which includes border properties.
16
+ // CCA has issues with borders on Text on iOS. (https://github.com/planningcenter/chat-mobile/pull/177)
17
+ // Our pattern is to apply boarders to a parent View instead.
18
+ type BorderKeys =
19
+ | 'borderWidth'
20
+ | 'borderBottomWidth'
21
+ | 'borderLeftWidth'
22
+ | 'borderRightWidth'
23
+ | 'borderTopWidth'
24
+ | 'borderColor'
25
+ | 'borderBottomColor'
26
+ | 'borderLeftColor'
27
+ | 'borderRightColor'
28
+ | 'borderTopColor'
29
+ | 'borderStyle'
30
+
31
+ export type TextStyle = Omit<ReactNativeTextStyle, BorderKeys> & {
32
+ [K in BorderKeys]?: never
33
+ }
34
+
11
35
  const VARIANTS = {
12
36
  plain: 'plain',
13
37
  secondary: 'secondary',
@@ -22,11 +46,15 @@ type VariantStyles = Record<VariantUnion, TextStyle>
22
46
  // ====== Component ================
23
47
  // =================================
24
48
 
25
- export interface TextProps extends ReactNativeTextProps {
49
+ export interface TextProps extends Omit<ReactNativeTextProps, 'style'> {
26
50
  /**
27
51
  * Changes the styles and size of the text.
28
52
  */
29
53
  variant?: VariantUnion
54
+ /**
55
+ * Text styles (border and background properties are not allowed)
56
+ */
57
+ style?: StyleProp<TextStyle>
30
58
  }
31
59
 
32
60
  export function Text({ style, variant = 'plain', children, ...props }: TextProps) {
@@ -8,7 +8,11 @@ import {
8
8
  useCreateAndroidRippleColor,
9
9
  useInteractionGhostBackgroundColor,
10
10
  } from '../../hooks'
11
- import { platformFontWeightBold, platformPressedOpacityStyle } from '../../utils'
11
+ import {
12
+ MAX_FONT_SIZE_MULTIPLIER_LANDMARK,
13
+ platformFontWeightBold,
14
+ platformPressedOpacityStyle,
15
+ } from '../../utils'
12
16
  import { Icon, IconString } from './icon'
13
17
  import { tokens } from '../../vendor/tapestry/tokens'
14
18
  import { Haptic } from '../../utils/native_adapters/configuration'
@@ -66,7 +70,7 @@ export function ToggleButton({
66
70
  allowFontScaling = true,
67
71
  iconNameLeft,
68
72
  iconNameRight,
69
- maxFontSizeMultiplier,
73
+ maxFontSizeMultiplier = MAX_FONT_SIZE_MULTIPLIER_LANDMARK,
70
74
  minimumFontScale,
71
75
  title,
72
76
  style,
@@ -1,11 +1,8 @@
1
1
  import { useNavigation } from '@react-navigation/native'
2
2
  import { useQueryErrorResetBoundary } from '@tanstack/react-query'
3
3
  import React, { PropsWithChildren, useEffect, useMemo } from 'react'
4
- import { StyleSheet, View } from 'react-native'
5
- import { useSafeAreaInsets } from 'react-native-safe-area-context'
6
- import { Button, Heading, Icon, Text, TextButton } from '../display'
7
- import { useTheme } from '../../hooks'
8
4
  import { ResponseError } from '../../utils/response_error'
5
+ import BlankState from '../primitive/blank_state_primitive'
9
6
 
10
7
  type ErrorBoundaryState = {
11
8
  error: ResponseError | Error | TypeError | null
@@ -108,54 +105,26 @@ function ResponseErrorView({ response }: { response: Response; onReset: () => vo
108
105
  }
109
106
 
110
107
  function ErrorContent({ heading, body }: { heading: string; body: string }) {
111
- const styles = useStyles()
112
108
  const navigation = useNavigation()
113
109
 
114
110
  return (
115
- <View style={styles.container}>
116
- <Icon name="general.outlinedTextMessage" size={32} color={styles.icon.color} />
117
- <View style={styles.information}>
118
- <Heading variant="h3" style={styles.heading}>
119
- {heading}
120
- </Heading>
121
- <Text style={styles.body}>{body}</Text>
122
- </View>
123
- <Button variant="outline" onPress={navigation.goBack} title="Go back" size="md" />
124
- <TextButton variant="tertiary" onPress={() => navigation.navigate('BugReport')}>
111
+ <BlankState.Root>
112
+ <BlankState.Imagery name="people.noTextMessage" />
113
+ <BlankState.Content>
114
+ <BlankState.Heading>{heading}</BlankState.Heading>
115
+ <BlankState.Text>{body}</BlankState.Text>
116
+ </BlankState.Content>
117
+ <BlankState.Button
118
+ title="Go back"
119
+ onPress={navigation.goBack}
120
+ size="md"
121
+ accessibilityRole="link"
122
+ />
123
+ <BlankState.TextButton onPress={() => navigation.navigate('BugReport')}>
125
124
  Report a bug
126
- </TextButton>
127
- </View>
125
+ </BlankState.TextButton>
126
+ </BlankState.Root>
128
127
  )
129
128
  }
130
129
 
131
- const useStyles = () => {
132
- const theme = useTheme()
133
- const { bottom } = useSafeAreaInsets()
134
- return StyleSheet.create({
135
- container: {
136
- flex: 1,
137
- justifyContent: 'center',
138
- alignItems: 'center',
139
- gap: 24,
140
- paddingHorizontal: 16,
141
- paddingBottom: bottom,
142
- },
143
- information: {
144
- alignItems: 'center',
145
- gap: 8,
146
- },
147
- heading: {
148
- textAlign: 'center',
149
- lineHeight: 20,
150
- },
151
- body: {
152
- textAlign: 'center',
153
- lineHeight: 20,
154
- },
155
- icon: {
156
- color: theme.colors.iconColorDefaultDisabled,
157
- },
158
- })
159
- }
160
-
161
130
  export default ErrorBoundary
@@ -1,9 +1,10 @@
1
1
  import React, { createContext, useContext, useEffect, useState } from 'react'
2
2
  import { StyleSheet, View, ViewProps } from 'react-native'
3
- import { useTheme } from '../../hooks'
3
+ import { useFontScale, useTheme } from '../../hooks'
4
4
  import { Icon, IconString } from '../display/icon'
5
5
  import { Image, ImageProps } from '../display/image'
6
6
  import { Spinner } from '../display/spinner'
7
+ import { MAX_FONT_SIZE_MULTIPLIER } from '../../utils'
7
8
 
8
9
  // =================================
9
10
  // ====== Exports ==================
@@ -146,8 +147,10 @@ interface AvatarImageProps extends Omit<ImageProps, 'source' | 'alt'> {
146
147
 
147
148
  function AvatarImage({ sourceUri, ...props }: AvatarImageProps) {
148
149
  const { size } = useAvatarContext()
150
+ const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
151
+ const scaledAvatarSize = AVATAR_PX[size] * fontScale
149
152
 
150
- return <Image source={{ uri: sourceUri }} loaderSize={AVATAR_PX[size]} {...props} alt="" />
153
+ return <Image source={{ uri: sourceUri }} loaderSize={scaledAvatarSize} {...props} alt="" />
151
154
  }
152
155
 
153
156
  AvatarImage.displayName = 'Avatar.Image'
@@ -171,12 +174,14 @@ interface AvatarImageFallbackProps {
171
174
  function AvatarImageFallback({ name = 'general.person' }: AvatarImageFallbackProps) {
172
175
  const { size } = useAvatarContext()
173
176
  const styles = useStyles()
177
+ const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
178
+ const scaledIconSize = AVATAR_FALLBACK_ICON_PX[size] * fontScale
174
179
 
175
180
  return (
176
181
  <View style={styles.fallbackContainer}>
177
182
  <Icon
178
183
  name={name}
179
- size={AVATAR_FALLBACK_ICON_PX[size]}
184
+ size={scaledIconSize}
180
185
  style={styles.fallbackIcon}
181
186
  accessibilityElementsHidden={true}
182
187
  />
@@ -309,12 +314,14 @@ AvatarGroup.displayName = 'Avatar.Group'
309
314
  function AvatarGroupLoader() {
310
315
  const { size, allImagesLoaded } = useAvatarContext()
311
316
  const styles = useStyles({ size })
317
+ const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
318
+ const scaledSpinnerSize = AVATAR_PX[size] * fontScale
312
319
 
313
320
  if (allImagesLoaded) return null
314
321
 
315
322
  return (
316
323
  <View style={styles.groupLoader}>
317
- <Spinner size={AVATAR_PX[size]} />
324
+ <Spinner size={scaledSpinnerSize} />
318
325
  </View>
319
326
  )
320
327
  }
@@ -349,12 +356,13 @@ interface Styles {
349
356
 
350
357
  const useStyles = ({ size = 'md', presence = 'offline' }: Styles = {}) => {
351
358
  const { colors } = useTheme()
359
+ const fontScale = useFontScale({ maxFontSizeMultiplier: MAX_FONT_SIZE_MULTIPLIER })
352
360
  const PRESENCE_COLOR = {
353
361
  online: colors.fillColorInteractionOnlineDefault,
354
362
  offline: colors.iconColorDefaultDisabled,
355
363
  }
356
- const presenceDiameter = AVATAR_PRESENCE_PX[size]
357
- const avatarDiameter = AVATAR_PX[size]
364
+ const presenceDiameter = AVATAR_PRESENCE_PX[size] * fontScale
365
+ const avatarDiameter = AVATAR_PX[size] * fontScale
358
366
  const groupGap = 1
359
367
 
360
368
  return StyleSheet.create({
@@ -0,0 +1,211 @@
1
+ import React, { FC, ReactNode } from 'react'
2
+ import { View, StyleSheet, ViewStyle } from 'react-native'
3
+ import { useTheme } from '../../hooks'
4
+ import {
5
+ Button,
6
+ Heading,
7
+ Icon,
8
+ TextButton,
9
+ Text,
10
+ type ButtonProps,
11
+ type HeadingProps,
12
+ type IconString,
13
+ type IconStyle,
14
+ type TextButtonProps,
15
+ type TextProps,
16
+ } from '../display'
17
+
18
+ // ========================================
19
+ // ====== Exports =========================
20
+ // ========================================
21
+
22
+ const BlankState = {
23
+ Root: BlankStateRoot,
24
+ Imagery: BlankStateImagery,
25
+ Content: BlankStateContent,
26
+ Heading: BlankStateHeading,
27
+ Text: BlankStateText,
28
+ Button: BlankStateButton,
29
+ TextButton: BlankStateTextButton,
30
+ } as const
31
+
32
+ type BlankStateComponents = {
33
+ Root: FC<BlankStateRootProps>
34
+ Imagery: FC<BlankStateImageryProps>
35
+ Content: FC<BlankStateContentProps>
36
+ Heading: FC<BlankStateHeadingProps>
37
+ Text: FC<BlankStateTextProps>
38
+ Button: FC<BlankStateButtonProps>
39
+ TextButton: FC<BlankStateTextButtonProps>
40
+ }
41
+
42
+ export default BlankState as BlankStateComponents
43
+ export type {
44
+ BlankStateRootProps,
45
+ BlankStateImageryProps,
46
+ BlankStateContentProps,
47
+ BlankStateHeadingProps,
48
+ BlankStateTextProps,
49
+ BlankStateButtonProps,
50
+ BlankStateTextButtonProps,
51
+ }
52
+
53
+ // ========================================
54
+ // ====== BlankStateRoot ==================
55
+ // ========================================
56
+
57
+ interface BlankStateRootProps {
58
+ children: ReactNode
59
+ style?: ViewStyle
60
+ }
61
+
62
+ function BlankStateRoot({ children, style }: BlankStateRootProps) {
63
+ const styles = useStyles()
64
+
65
+ return <View style={[styles.container, style]}>{children}</View>
66
+ }
67
+
68
+ BlankStateRoot.displayName = 'BlankState.Root'
69
+
70
+ // ========================================
71
+ // ====== BlankStateImagery ===============
72
+ // ========================================
73
+
74
+ interface BlankStateImageryProps {
75
+ name: IconString
76
+ size?: number
77
+ style?: IconStyle
78
+ }
79
+
80
+ function BlankStateImagery({ name, size = 32, style }: BlankStateImageryProps) {
81
+ const styles = useStyles()
82
+
83
+ /*
84
+ NOTE:
85
+ BlankState.Imagery will eventually return more then just an Icon component
86
+ Eventually it will need to return SVG illustrations from the theme or internally for Services Mobile.
87
+ This first step of using a more abstract component just allows us to keep this component open to change, without being overly perscriptive on how the change should be implomented.
88
+
89
+ */
90
+
91
+ return <Icon name={name} size={size} style={[styles.imagery, style]} />
92
+ }
93
+
94
+ BlankStateImagery.displayName = 'BlankState.Imagery'
95
+
96
+ // ========================================
97
+ // ====== BlankStateContent ===============
98
+ // ========================================
99
+
100
+ interface BlankStateContentProps {
101
+ children: ReactNode
102
+ style?: ViewStyle
103
+ }
104
+
105
+ function BlankStateContent({ children, style }: BlankStateContentProps) {
106
+ const styles = useStyles()
107
+
108
+ return <View style={[styles.content, style]}>{children}</View>
109
+ }
110
+
111
+ BlankStateContent.displayName = 'BlankState.Content'
112
+
113
+ // ========================================
114
+ // ====== BlankStateHeading ===============
115
+ // ========================================
116
+
117
+ interface BlankStateHeadingProps {
118
+ children: ReactNode
119
+ style?: HeadingProps['style']
120
+ }
121
+
122
+ function BlankStateHeading({ children, style }: BlankStateHeadingProps) {
123
+ const styles = useStyles()
124
+
125
+ return (
126
+ <Heading variant="h3" style={[styles.heading, style]}>
127
+ {children}
128
+ </Heading>
129
+ )
130
+ }
131
+
132
+ BlankStateHeading.displayName = 'BlankState.Heading'
133
+
134
+ // ========================================
135
+ // ====== BlankStateText ==================
136
+ // ========================================
137
+
138
+ interface BlankStateTextProps {
139
+ children: ReactNode
140
+ style?: TextProps['style']
141
+ }
142
+
143
+ function BlankStateText({ children, style }: BlankStateTextProps) {
144
+ const styles = useStyles()
145
+
146
+ return (
147
+ <Text variant="tertiary" style={[styles.text, style]}>
148
+ {children}
149
+ </Text>
150
+ )
151
+ }
152
+
153
+ BlankStateText.displayName = 'BlankState.Text'
154
+
155
+ // ========================================
156
+ // ====== BlankStateButton ================
157
+ // ========================================
158
+
159
+ interface BlankStateButtonProps extends ButtonProps {}
160
+
161
+ function BlankStateButton(props: BlankStateButtonProps) {
162
+ return <Button variant="outline" size="sm" {...props} />
163
+ }
164
+
165
+ BlankStateButton.displayName = 'BlankState.Button'
166
+
167
+ // ========================================
168
+ // ====== BlankStateTextButton ================
169
+ // ========================================
170
+
171
+ interface BlankStateTextButtonProps extends TextButtonProps {}
172
+
173
+ function BlankStateTextButton(props: BlankStateTextButtonProps) {
174
+ return <TextButton variant="tertiary" {...props} />
175
+ }
176
+
177
+ BlankStateTextButton.displayName = 'BlankState.TextButton'
178
+
179
+ // ========================================
180
+ // ====== Styles ==========================
181
+ // ========================================
182
+
183
+ const useStyles = () => {
184
+ const { colors } = useTheme()
185
+
186
+ return StyleSheet.create({
187
+ container: {
188
+ flex: 1,
189
+ alignItems: 'center',
190
+ justifyContent: 'center',
191
+ gap: 16,
192
+ padding: 16,
193
+ },
194
+ imagery: {
195
+ color: colors.iconColorDefaultDisabled,
196
+ },
197
+ content: {
198
+ alignItems: 'center',
199
+ gap: 4,
200
+ maxWidth: 250,
201
+ },
202
+ heading: {
203
+ textAlign: 'center',
204
+ color: colors.textColorDefaultSecondary,
205
+ },
206
+ text: {
207
+ textAlign: 'center',
208
+ color: colors.textColorDefaultSecondary,
209
+ },
210
+ })
211
+ }
@@ -42,7 +42,7 @@ import {
42
42
  MessageReadReceiptsScreenOptions,
43
43
  } from '../screens/conversation/message_read_receipts_screen'
44
44
  import { Platform } from 'react-native'
45
- import { HeaderSubmitButton } from '../components/display/platform_modal_header_buttons'
45
+ import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
46
46
  import { TeamConversationScreen } from '../screens/team_conversation_screen'
47
47
  import { CardStyleInterpolators } from '@react-navigation/stack'
48
48
 
@@ -63,7 +63,7 @@ export const NewConversationStack = createNativeStackNavigator({
63
63
  options: ({ navigation }) => ({
64
64
  title: 'New conversation',
65
65
  headerRight: (props: NativeStackHeaderRightProps) => (
66
- <HeaderSubmitButton {...props} onPress={navigation.goBack} title="Cancel" />
66
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Cancel" />
67
67
  ),
68
68
  headerBackVisible: false,
69
69
  }),
@@ -73,7 +73,7 @@ export const NewConversationStack = createNativeStackNavigator({
73
73
  options: ({ navigation, route }) => ({
74
74
  title: 'New conversation',
75
75
  headerRight: (props: NativeStackHeaderRightProps) => (
76
- <HeaderSubmitButton
76
+ <HeaderTextButton
77
77
  {...props}
78
78
  onPress={() => navigation.popTo('Conversations', route.params)}
79
79
  title="Cancel"
@@ -86,7 +86,7 @@ export const NewConversationStack = createNativeStackNavigator({
86
86
  options: ({ navigation, route }) => ({
87
87
  title: 'New conversation',
88
88
  headerRight: (props: NativeStackHeaderRightProps) => (
89
- <HeaderSubmitButton
89
+ <HeaderTextButton
90
90
  {...props}
91
91
  onPress={() => navigation.popTo('Conversations', route.params)}
92
92
  title="Cancel"
@@ -104,7 +104,7 @@ export const NewConversationStack = createNativeStackNavigator({
104
104
  title: 'New conversation',
105
105
  headerLeft: () => null,
106
106
  headerRight: (props: NativeStackHeaderRightProps) => (
107
- <HeaderSubmitButton
107
+ <HeaderTextButton
108
108
  {...props}
109
109
  onPress={() => navigation.getParent()?.goBack()}
110
110
  title="Cancel"
@@ -195,7 +195,7 @@ export const ChatStack = createNativeStackNavigator({
195
195
  presentation: 'modal',
196
196
  title: 'Conversation details',
197
197
  headerRight: (props: NativeStackHeaderRightProps) => (
198
- <HeaderSubmitButton {...props} onPress={navigation.goBack} title="Done" />
198
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
199
199
  ),
200
200
  }),
201
201
  },