@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.
- package/build/components/conversation/empty_conversation_blank_state.d.ts.map +1 -1
- package/build/components/conversation/empty_conversation_blank_state.js +10 -2
- package/build/components/conversation/empty_conversation_blank_state.js.map +1 -1
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +7 -2
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/display/action_button.d.ts.map +1 -1
- package/build/components/display/action_button.js +2 -1
- package/build/components/display/action_button.js.map +1 -1
- package/build/components/display/badge.js +5 -5
- package/build/components/display/badge.js.map +1 -1
- package/build/components/display/index.d.ts +0 -1
- package/build/components/display/index.d.ts.map +1 -1
- package/build/components/display/index.js +0 -1
- package/build/components/display/index.js.map +1 -1
- package/build/components/display/platform_modal_header_buttons.d.ts +4 -4
- package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -1
- package/build/components/display/platform_modal_header_buttons.js +2 -2
- package/build/components/display/platform_modal_header_buttons.js.map +1 -1
- package/build/components/display/text.d.ts +10 -2
- package/build/components/display/text.d.ts.map +1 -1
- package/build/components/display/text.js +0 -3
- package/build/components/display/text.js.map +1 -1
- package/build/components/display/toggle_button.d.ts.map +1 -1
- package/build/components/display/toggle_button.js +2 -2
- package/build/components/display/toggle_button.js.map +1 -1
- package/build/components/page/error_boundary.d.ts.map +1 -1
- package/build/components/page/error_boundary.js +11 -46
- package/build/components/page/error_boundary.js.map +1 -1
- package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
- package/build/components/primitive/avatar_primitive.js +14 -6
- package/build/components/primitive/avatar_primitive.js.map +1 -1
- package/build/components/primitive/blank_state_primitive.d.ts +41 -0
- package/build/components/primitive/blank_state_primitive.d.ts.map +1 -0
- package/build/components/primitive/blank_state_primitive.js +93 -0
- package/build/components/primitive/blank_state_primitive.js.map +1 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +6 -6
- package/build/navigation/index.js.map +1 -1
- package/build/screens/bug_report_screen.d.ts.map +1 -1
- package/build/screens/bug_report_screen.js +17 -11
- package/build/screens/bug_report_screen.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +3 -3
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js +8 -2
- package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js.map +1 -1
- package/build/screens/conversation_new/components/filter_by_plan.js +2 -2
- package/build/screens/conversation_new/components/filter_by_plan.js.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +8 -7
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js +13 -3
- package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js.map +1 -1
- package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
- package/build/screens/conversations/components/list_header_component.js +2 -1
- package/build/screens/conversations/components/list_header_component.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +2 -2
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/screens/design_system_screen.js +13 -8
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/screens/send_giphy_screen.d.ts.map +1 -1
- package/build/screens/send_giphy_screen.js +10 -5
- package/build/screens/send_giphy_screen.js.map +1 -1
- package/build/utils/styles.d.ts +1 -0
- package/build/utils/styles.d.ts.map +1 -1
- package/build/utils/styles.js +1 -0
- package/build/utils/styles.js.map +1 -1
- package/package.json +2 -2
- package/src/components/conversation/empty_conversation_blank_state.tsx +10 -6
- package/src/components/conversations/conversations.tsx +7 -2
- package/src/components/display/action_button.tsx +2 -0
- package/src/components/display/badge.tsx +5 -5
- package/src/components/display/index.ts +0 -1
- package/src/components/display/platform_modal_header_buttons.tsx +6 -6
- package/src/components/display/text.tsx +30 -2
- package/src/components/display/toggle_button.tsx +6 -2
- package/src/components/page/error_boundary.tsx +16 -47
- package/src/components/primitive/avatar_primitive.tsx +14 -6
- package/src/components/primitive/blank_state_primitive.tsx +211 -0
- package/src/navigation/index.tsx +6 -6
- package/src/screens/bug_report_screen.tsx +22 -20
- package/src/screens/conversation_details_screen.tsx +13 -4
- package/src/screens/conversation_filter_recipients/conversation_filter_recipients_screen.tsx +11 -2
- package/src/screens/conversation_new/components/filter_by_plan.tsx +2 -2
- package/src/screens/conversation_screen.tsx +13 -11
- package/src/screens/conversation_select_recipients/conversation_select_recipients_screen.tsx +17 -6
- package/src/screens/conversations/components/list_header_component.tsx +6 -1
- package/src/screens/conversations/conversations_screen.tsx +6 -2
- package/src/screens/design_system_screen.tsx +17 -13
- package/src/screens/send_giphy_screen.tsx +10 -11
- package/src/utils/styles.ts +1 -0
- package/build/components/display/blank_state.d.ts +0 -18
- package/build/components/display/blank_state.d.ts.map +0 -1
- package/build/components/display/blank_state.js +0 -47
- package/build/components/display/blank_state.js.map +0 -1
- package/build/navigation/header.d.ts +0 -10
- package/build/navigation/header.d.ts.map +0 -1
- package/build/navigation/header.js +0 -16
- package/build/navigation/header.js.map +0 -1
- package/src/components/display/blank_state.tsx +0 -76
- package/src/navigation/header.tsx +0 -24
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BlankState from '../primitive/blank_state_primitive'
|
|
2
2
|
|
|
3
3
|
export const EmptyConversationBlankState = () => {
|
|
4
4
|
return (
|
|
5
|
-
<BlankState
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
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
|
|
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
|
},
|
|
@@ -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
|
|
7
|
+
interface HeaderTextButtonProps {
|
|
8
8
|
onPress: () => void
|
|
9
9
|
title?: string
|
|
10
10
|
disabled?: boolean
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const
|
|
13
|
+
export const HeaderTextButton = ({
|
|
14
14
|
onPress,
|
|
15
15
|
title = 'Submit',
|
|
16
16
|
...props
|
|
17
|
-
}:
|
|
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
|
|
32
|
+
interface HeaderDismissButtonProps {
|
|
33
33
|
onPress: () => void
|
|
34
34
|
title?: string
|
|
35
35
|
tintColor?: ColorValue
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export const
|
|
38
|
+
export const HeaderDismissButton = ({
|
|
39
39
|
onPress,
|
|
40
40
|
title = 'Cancel',
|
|
41
41
|
tintColor,
|
|
42
42
|
...props
|
|
43
|
-
}:
|
|
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 {
|
|
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 {
|
|
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
|
-
<
|
|
116
|
-
<
|
|
117
|
-
<
|
|
118
|
-
<Heading
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
</
|
|
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={
|
|
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={
|
|
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={
|
|
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
|
+
}
|
package/src/navigation/index.tsx
CHANGED
|
@@ -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 {
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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
|
-
<
|
|
198
|
+
<HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
|
|
199
199
|
),
|
|
200
200
|
}),
|
|
201
201
|
},
|