@planningcenter/chat-react-native 1.5.0 → 1.6.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 (206) hide show
  1. package/build/components/conversations.d.ts.map +1 -1
  2. package/build/components/conversations.js +29 -8
  3. package/build/components/conversations.js.map +1 -1
  4. package/build/components/display/button.d.ts +71 -0
  5. package/build/components/display/button.d.ts.map +1 -0
  6. package/build/components/display/button.js +136 -0
  7. package/build/components/display/button.js.map +1 -0
  8. package/build/components/display/button_color_utils.d.ts +24 -0
  9. package/build/components/display/button_color_utils.d.ts.map +1 -0
  10. package/build/components/display/button_color_utils.js +43 -0
  11. package/build/components/display/button_color_utils.js.map +1 -0
  12. package/build/components/display/heading.d.ts +4 -0
  13. package/build/components/display/heading.d.ts.map +1 -1
  14. package/build/components/display/heading.js +3 -0
  15. package/build/components/display/heading.js.map +1 -1
  16. package/build/components/display/icon.d.ts +8 -4
  17. package/build/components/display/icon.d.ts.map +1 -1
  18. package/build/components/display/icon.js +21 -13
  19. package/build/components/display/icon.js.map +1 -1
  20. package/build/components/display/image.d.ts +7 -2
  21. package/build/components/display/image.d.ts.map +1 -1
  22. package/build/components/display/image.js +5 -5
  23. package/build/components/display/image.js.map +1 -1
  24. package/build/components/display/index.d.ts +10 -7
  25. package/build/components/display/index.d.ts.map +1 -1
  26. package/build/components/display/index.js +10 -7
  27. package/build/components/display/index.js.map +1 -1
  28. package/build/components/display/spinner.d.ts +5 -1
  29. package/build/components/display/spinner.d.ts.map +1 -1
  30. package/build/components/display/spinner.js +19 -13
  31. package/build/components/display/spinner.js.map +1 -1
  32. package/build/components/display/text.d.ts +13 -3
  33. package/build/components/display/text.d.ts.map +1 -1
  34. package/build/components/display/text.js +17 -5
  35. package/build/components/display/text.js.map +1 -1
  36. package/build/components/display/text_button.d.ts +37 -0
  37. package/build/components/display/text_button.d.ts.map +1 -0
  38. package/build/components/display/text_button.js +36 -0
  39. package/build/components/display/text_button.js.map +1 -0
  40. package/build/components/display/text_inline_button.d.ts +12 -0
  41. package/build/components/display/text_inline_button.d.ts.map +1 -0
  42. package/build/components/display/text_inline_button.js +53 -0
  43. package/build/components/display/text_inline_button.js.map +1 -0
  44. package/build/components/index.d.ts +1 -0
  45. package/build/components/index.d.ts.map +1 -1
  46. package/build/components/index.js +1 -0
  47. package/build/components/index.js.map +1 -1
  48. package/build/components/primitive/avatar_primitive.d.ts +1 -1
  49. package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
  50. package/build/components/primitive/avatar_primitive.js +6 -9
  51. package/build/components/primitive/avatar_primitive.js.map +1 -1
  52. package/build/contexts/api_provider.d.ts +4 -6
  53. package/build/contexts/api_provider.d.ts.map +1 -1
  54. package/build/contexts/api_provider.js +13 -20
  55. package/build/contexts/api_provider.js.map +1 -1
  56. package/build/contexts/chat_context.d.ts +7 -5
  57. package/build/contexts/chat_context.d.ts.map +1 -1
  58. package/build/contexts/chat_context.js +40 -4
  59. package/build/contexts/chat_context.js.map +1 -1
  60. package/build/hooks/index.d.ts +4 -0
  61. package/build/hooks/index.d.ts.map +1 -1
  62. package/build/hooks/index.js +4 -0
  63. package/build/hooks/index.js.map +1 -1
  64. package/build/hooks/use_create_android_ripple_color.d.ts +4 -0
  65. package/build/hooks/use_create_android_ripple_color.d.ts.map +1 -0
  66. package/build/hooks/use_create_android_ripple_color.js +15 -0
  67. package/build/hooks/use_create_android_ripple_color.js.map +1 -0
  68. package/build/hooks/use_current_person.d.ts +3 -0
  69. package/build/hooks/use_current_person.d.ts.map +1 -0
  70. package/build/hooks/use_current_person.js +13 -0
  71. package/build/hooks/use_current_person.js.map +1 -0
  72. package/build/hooks/use_font_scale.d.ts +4 -0
  73. package/build/hooks/use_font_scale.d.ts.map +1 -0
  74. package/build/hooks/use_font_scale.js +8 -0
  75. package/build/hooks/use_font_scale.js.map +1 -0
  76. package/build/hooks/use_suspense_api.d.ts +61 -0
  77. package/build/hooks/use_suspense_api.d.ts.map +1 -0
  78. package/build/hooks/use_suspense_api.js +39 -0
  79. package/build/hooks/use_suspense_api.js.map +1 -0
  80. package/build/navigation/index.d.ts +1 -0
  81. package/build/navigation/index.d.ts.map +1 -1
  82. package/build/navigation/index.js +7 -4
  83. package/build/navigation/index.js.map +1 -1
  84. package/build/screens/conversation_screen.d.ts.map +1 -1
  85. package/build/screens/conversation_screen.js +59 -6
  86. package/build/screens/conversation_screen.js.map +1 -1
  87. package/build/screens/display.d.ts.map +1 -1
  88. package/build/screens/display.js +277 -51
  89. package/build/screens/display.js.map +1 -1
  90. package/build/screens/not_found.js +1 -1
  91. package/build/screens/not_found.js.map +1 -1
  92. package/build/types/api_primitives.d.ts +23 -0
  93. package/build/types/api_primitives.d.ts.map +1 -0
  94. package/build/types/api_primitives.js +2 -0
  95. package/build/types/api_primitives.js.map +1 -0
  96. package/build/types/index.d.ts +4 -0
  97. package/build/types/index.d.ts.map +1 -0
  98. package/build/types/index.js +4 -0
  99. package/build/types/index.js.map +1 -0
  100. package/build/types/resources/conversation.d.ts +15 -0
  101. package/build/types/resources/conversation.d.ts.map +1 -0
  102. package/build/types/resources/conversation.js +2 -0
  103. package/build/types/resources/conversation.js.map +1 -0
  104. package/build/types/resources/index.d.ts +5 -0
  105. package/build/types/resources/index.d.ts.map +1 -0
  106. package/build/types/resources/index.js +5 -0
  107. package/build/types/resources/index.js.map +1 -0
  108. package/build/types/resources/message.d.ts +16 -0
  109. package/build/types/resources/message.d.ts.map +1 -0
  110. package/build/types/resources/message.js +2 -0
  111. package/build/types/resources/message.js.map +1 -0
  112. package/build/types/resources/oauth_token.d.ts +9 -0
  113. package/build/types/resources/oauth_token.d.ts.map +1 -0
  114. package/build/types/resources/oauth_token.js +2 -0
  115. package/build/types/resources/oauth_token.js.map +1 -0
  116. package/build/types/resources/person.d.ts +9 -0
  117. package/build/types/resources/person.d.ts.map +1 -0
  118. package/build/types/resources/person.js +2 -0
  119. package/build/types/resources/person.js.map +1 -0
  120. package/build/types/resources/reaction.d.ts +10 -0
  121. package/build/types/resources/reaction.d.ts.map +1 -0
  122. package/build/types/resources/reaction.js +2 -0
  123. package/build/types/resources/reaction.js.map +1 -0
  124. package/build/types/utils/index.d.ts +4 -0
  125. package/build/types/utils/index.d.ts.map +1 -0
  126. package/build/types/utils/index.js +4 -0
  127. package/build/types/utils/index.js.map +1 -0
  128. package/build/utils/client/client.d.ts +21 -12
  129. package/build/utils/client/client.d.ts.map +1 -1
  130. package/build/utils/client/client.js +24 -22
  131. package/build/utils/client/client.js.map +1 -1
  132. package/build/utils/index.d.ts +1 -0
  133. package/build/utils/index.d.ts.map +1 -1
  134. package/build/utils/index.js +1 -0
  135. package/build/utils/index.js.map +1 -1
  136. package/build/utils/session.d.ts +0 -5
  137. package/build/utils/session.d.ts.map +1 -1
  138. package/build/utils/session.js +0 -10
  139. package/build/utils/session.js.map +1 -1
  140. package/build/utils/styles.d.ts +5 -0
  141. package/build/utils/styles.d.ts.map +1 -1
  142. package/build/utils/styles.js +9 -0
  143. package/build/utils/styles.js.map +1 -1
  144. package/build/utils/theme.d.ts +3 -1
  145. package/build/utils/theme.d.ts.map +1 -1
  146. package/build/utils/theme.js +6 -2
  147. package/build/utils/theme.js.map +1 -1
  148. package/build/vendor/tapestry/alias_tokens_color_map.d.ts +8 -0
  149. package/build/vendor/tapestry/alias_tokens_color_map.d.ts.map +1 -1
  150. package/build/vendor/tapestry/alias_tokens_color_map.js +8 -0
  151. package/build/vendor/tapestry/alias_tokens_color_map.js.map +1 -1
  152. package/build/vendor/tapestry/tokens.d.ts +21 -0
  153. package/build/vendor/tapestry/tokens.d.ts.map +1 -1
  154. package/build/vendor/tapestry/tokens.js +21 -0
  155. package/build/vendor/tapestry/tokens.js.map +1 -1
  156. package/package.json +4 -3
  157. package/src/__tests__/client.ts +72 -19
  158. package/src/__tests__/session.ts +0 -11
  159. package/src/__utils__/handlers.ts +1 -1
  160. package/src/components/conversations.tsx +33 -11
  161. package/src/components/display/button.tsx +293 -0
  162. package/src/components/display/button_color_utils.ts +72 -0
  163. package/src/components/display/heading.tsx +12 -0
  164. package/src/components/display/icon.tsx +35 -16
  165. package/src/components/display/image.tsx +29 -7
  166. package/src/components/display/index.ts +10 -7
  167. package/src/components/display/spinner.tsx +42 -13
  168. package/src/components/display/text.tsx +34 -13
  169. package/src/components/display/text_button.tsx +102 -0
  170. package/src/components/display/text_inline_button.tsx +91 -0
  171. package/src/components/index.tsx +1 -0
  172. package/src/components/primitive/avatar_primitive.tsx +12 -6
  173. package/src/contexts/api_provider.tsx +18 -26
  174. package/src/contexts/chat_context.tsx +61 -7
  175. package/src/hooks/index.ts +4 -0
  176. package/src/hooks/use_create_android_ripple_color.ts +18 -0
  177. package/src/hooks/use_current_person.ts +15 -0
  178. package/src/hooks/use_font_scale.ts +9 -0
  179. package/src/hooks/use_suspense_api.ts +60 -0
  180. package/src/navigation/index.tsx +14 -4
  181. package/src/screens/conversation_screen.tsx +83 -7
  182. package/src/screens/display.tsx +447 -51
  183. package/src/screens/not_found.tsx +1 -1
  184. package/src/types/api_primitives.ts +24 -0
  185. package/src/types/index.ts +3 -0
  186. package/src/types/resources/conversation.ts +15 -0
  187. package/src/types/resources/index.ts +4 -0
  188. package/src/types/resources/message.ts +18 -0
  189. package/src/types/resources/oauth_token.ts +8 -0
  190. package/src/types/resources/person.ts +9 -0
  191. package/src/types/resources/reaction.ts +9 -0
  192. package/src/types/utils/index.ts +6 -0
  193. package/src/utils/client/client.ts +41 -34
  194. package/src/utils/client/types.d.ts +2 -0
  195. package/src/utils/index.ts +1 -0
  196. package/src/utils/session.ts +0 -13
  197. package/src/utils/styles.ts +12 -0
  198. package/src/utils/theme.ts +9 -3
  199. package/src/vendor/tapestry/alias_tokens_color_map.ts +12 -0
  200. package/src/vendor/tapestry/tokens.ts +21 -0
  201. package/build/utils/api.d.ts +0 -9
  202. package/build/utils/api.d.ts.map +0 -1
  203. package/build/utils/api.js +0 -36
  204. package/build/utils/api.js.map +0 -1
  205. package/src/types.d.ts +0 -35
  206. package/src/utils/api.ts +0 -47
@@ -1,7 +1,10 @@
1
- import { StaticScreenProps } from '@react-navigation/native'
2
- import React from 'react'
3
- import { StyleSheet, View } from 'react-native'
1
+ import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
+ import React, { useEffect } from 'react'
3
+ import { FlatList, SafeAreaView, StyleSheet, TextInput, View } from 'react-native'
4
4
  import { Text } from '../components/display'
5
+ import { useSuspenseGet, useSuspensePaginator } from '../hooks/use_suspense_api'
6
+ import { ConversationResource, MessageResource } from '../types'
7
+ import { useTheme } from '../hooks'
5
8
 
6
9
  export type ConversationScreenProps = StaticScreenProps<{
7
10
  conversation_id: string
@@ -9,17 +12,90 @@ export type ConversationScreenProps = StaticScreenProps<{
9
12
  }>
10
13
 
11
14
  export function ConversationScreen({ route }: ConversationScreenProps) {
15
+ const navigation = useNavigation()
16
+ const { conversation_id } = route.params
17
+
18
+ const { data: conversation } = useSuspenseGet<ConversationResource>({
19
+ url: `/me/conversations/${conversation_id}`,
20
+ data: {
21
+ fields: {
22
+ Conversation: ['title'],
23
+ },
24
+ },
25
+ })
26
+
27
+ const { data, refetch, isRefetching, fetchNextPage } = useSuspensePaginator<MessageResource>({
28
+ url: `/me/conversations/${conversation_id}/messages`,
29
+ data: {
30
+ perPage: 25,
31
+ fields: {
32
+ Message: ['text', 'mine'],
33
+ },
34
+ },
35
+ })
36
+
37
+ useEffect(() => {
38
+ navigation.setOptions({ title: conversation?.title })
39
+ }, [conversation, conversation_id, navigation])
40
+
12
41
  return (
13
- <View style={styles.container}>
14
- <Text>{JSON.stringify(route.params, null, 2)}</Text>
15
- </View>
42
+ <SafeAreaView style={styles.container}>
43
+ <FlatList
44
+ inverted
45
+ contentContainerStyle={styles.listContainer}
46
+ refreshing={isRefetching}
47
+ onRefresh={refetch}
48
+ data={data}
49
+ keyExtractor={item => item.id}
50
+ renderItem={({ item }) => <Message {...item} />}
51
+ onEndReached={() => fetchNextPage()}
52
+ />
53
+ <View style={styles.textInputContainer}>
54
+ <TextInput
55
+ aria-disabled={true}
56
+ placeholder="Send a message"
57
+ onChangeText={() => console.log('TODO: Implement sending a message')}
58
+ value=""
59
+ style={styles.textInput}
60
+ />
61
+ </View>
62
+ </SafeAreaView>
16
63
  )
17
64
  }
18
65
 
66
+ function Message(message: MessageResource) {
67
+ const { text } = message
68
+ const styles = useMessageStyles(message)
69
+
70
+ return <Text style={styles.message}>{text}</Text>
71
+ }
72
+
73
+ const useMessageStyles = ({ mine }: MessageResource) => {
74
+ const { colors } = useTheme()
75
+
76
+ return StyleSheet.create({
77
+ message: {
78
+ alignSelf: mine ? 'flex-end' : 'flex-start',
79
+ backgroundColor: mine ? colors.fillColorNeutral040 : colors.fillColorNeutral050Base,
80
+ borderRadius: 16,
81
+ borderBottomLeftRadius: mine ? 16 : 0,
82
+ borderBottomRightRadius: mine ? 0 : 16,
83
+ padding: 12,
84
+ color: colors.textColorDefaultPrimary,
85
+ },
86
+ })
87
+ }
88
+
19
89
  const styles = StyleSheet.create({
20
90
  container: {
21
91
  flex: 1,
22
92
  justifyContent: 'center',
23
- gap: 8,
24
93
  },
94
+ listContainer: {
95
+ gap: 12,
96
+ paddingHorizontal: 16,
97
+ paddingTop: 12,
98
+ },
99
+ textInputContainer: { borderTopWidth: 1, padding: 12 },
100
+ textInput: { borderRadius: 16, borderWidth: 1, padding: 12 },
25
101
  })
@@ -1,8 +1,20 @@
1
- import React from 'react'
2
- import { ScrollView, StyleSheet, View } from 'react-native'
1
+ import React, { useState } from 'react'
2
+ import { Alert, Pressable, ScrollView, StyleSheet, View } from 'react-native'
3
+ import type { ViewStyle } from 'react-native'
3
4
  import { useTheme } from '../hooks'
4
- import { Avatar, AvatarGroup, Heading, Icon, Image, Spinner, Text } from '../components/display'
5
- import { space } from '../utils/space'
5
+ import {
6
+ Avatar,
7
+ AvatarGroup,
8
+ Button,
9
+ Heading,
10
+ Icon,
11
+ Image,
12
+ Spinner,
13
+ Text,
14
+ TextButton,
15
+ TextInlineButton,
16
+ } from '../components/display'
17
+ import { space, MAX_FONT_SIZE_MULTIPLIER, platformPressedOpacityStyle } from '../utils'
6
18
 
7
19
  const URL = {
8
20
  image: 'https://picsum.photos/seed/picsum/200',
@@ -23,66 +35,442 @@ const URL = {
23
35
  ],
24
36
  }
25
37
 
38
+ const buttonPress = () => Alert.alert('Button clicked')
39
+
26
40
  export function DisplayScreen() {
27
41
  const styles = useStyles()
28
42
 
29
43
  return (
30
44
  <ScrollView contentContainerStyle={styles.container} style={styles.scrollView}>
31
- <View style={styles.column}>
32
- <View style={[styles.row, styles.spinnerContainer]}>
33
- <Spinner size={24} />
34
- </View>
35
- <View style={styles.row}>
36
- <Image source={{ uri: URL.broken }} style={styles.image} />
37
- <Image source={{ uri: URL.image }} style={styles.image} />
38
- </View>
39
- <View style={styles.row}>
40
- <Avatar sourceUri={URL.broken} />
41
- <Avatar size="md" sourceUri={URL.avatar_fallback} />
42
- <Avatar sourceUri={URL.avatar} />
43
- </View>
44
- <View style={styles.row}>
45
- <Avatar presence="offline" sourceUri={URL.broken} />
46
- <Avatar presence="online" size="md" sourceUri={URL.avatar_fallback} />
47
- <Avatar presence="offline" sourceUri={URL.avatar} />
48
- </View>
49
- <View style={styles.row}>
50
- <AvatarGroup sourceUris={[URL.broken]} />
51
- <AvatarGroup sourceUris={[URL.broken, URL.broken, ...URL.two_avatars]} />
52
- <AvatarGroup sourceUris={[URL.avatar]} />
53
- <AvatarGroup sourceUris={URL.two_avatars} />
54
- <AvatarGroup sourceUris={URL.three_avatars} />
55
- <AvatarGroup sourceUris={URL.four_avatars} />
56
- </View>
57
- <View style={styles.row}>
58
- <Icon name="missingIcon" size={20} />
59
- <Icon name="general.textMessage" size={20} />
60
- <Icon name="churchCenter.sort" style={styles.icon} />
61
- </View>
62
- <View style={styles.row}>
63
- <Text>Plain text</Text>
64
- <Text variant="secondary">Secondary</Text>
65
- <Text variant="tertiary">Tertiary</Text>
66
- <Text variant="footnote">Footnote</Text>
67
- </View>
68
- <View style={styles.row}>
69
- <Heading>Heading 1</Heading>
70
- <Heading variant="h2">Heading 2</Heading>
71
- <Heading variant="h3">Heading 3</Heading>
72
- <Heading variant="h4">Heading 4</Heading>
73
- </View>
74
- </View>
45
+ <CollapsableSection title="Molecules">
46
+ <Row>
47
+ <Text>🚧 Coming soon! 🚧</Text>
48
+ </Row>
49
+ </CollapsableSection>
50
+ <CollapsableSection title="Atoms" isLast>
51
+ <Group
52
+ title="Spinner"
53
+ description="Loading indicators that can be used within or close to atomic components. Not intended for full-screen loading."
54
+ >
55
+ <Row style={styles.spinnerContainer}>
56
+ <Spinner size={24} />
57
+ </Row>
58
+ </Group>
59
+ <Group
60
+ title="Image"
61
+ description="Foundational way of displaying images. Loading or broken images will fallback to show a spinner. Hide decortive images from screen readers with `alt=''`."
62
+ >
63
+ <Row>
64
+ <Image source={{ uri: URL.broken }} style={styles.image} alt="Mountain sunrise" />
65
+ <Image source={{ uri: URL.image }} style={styles.image} alt="Mountain sunrise" />
66
+ <Image source={{ uri: URL.image }} style={styles.image} alt="" />
67
+ </Row>
68
+ </Group>
69
+ <Group
70
+ title="Avatar"
71
+ description='Displays the profile image for a user in different sizes and has a loading fallback. Can optionally show an online/offline "presence" indicator.'
72
+ >
73
+ <Row>
74
+ <Avatar sourceUri={URL.broken} />
75
+ <Avatar size="md" sourceUri={URL.avatar_fallback} />
76
+ <Avatar sourceUri={URL.avatar} />
77
+ </Row>
78
+ <Row>
79
+ <Avatar presence="offline" sourceUri={URL.broken} />
80
+ <Avatar presence="online" size="md" sourceUri={URL.avatar_fallback} />
81
+ <Avatar presence="offline" sourceUri={URL.avatar} />
82
+ </Row>
83
+ </Group>
84
+ <Group
85
+ title="AvatarGroup"
86
+ description="Shows 1-4 images in a grid at different sizes. Loading fallback shows until all images successfully load."
87
+ >
88
+ <Row>
89
+ <AvatarGroup sourceUris={[URL.broken]} />
90
+ <AvatarGroup sourceUris={[URL.broken, URL.broken, ...URL.two_avatars]} />
91
+ <AvatarGroup sourceUris={[URL.avatar]} />
92
+ <AvatarGroup sourceUris={URL.two_avatars} />
93
+ <AvatarGroup sourceUris={URL.three_avatars} />
94
+ <AvatarGroup sourceUris={URL.four_avatars} />
95
+ </Row>
96
+ </Group>
97
+ <Group
98
+ title="Icon"
99
+ description="Displays any icon from @planningcenter/icons. Missing icons will fallback to a grey circle. Styling with `fontSize` will allow it to scale with the device's text a11y size."
100
+ >
101
+ <Row>
102
+ <Icon name="missingIcon" size={20} />
103
+ <Icon name="general.textMessage" size={20} />
104
+ <Icon name="churchCenter.sort" style={styles.icon} />
105
+ </Row>
106
+ </Group>
107
+ <Group
108
+ title="Button"
109
+ description="Feature fill and outline variants for primary and danger usecases, along with disabled & loading states. Optionally shows icons to the left and right of the text."
110
+ >
111
+ <Row>
112
+ <Button onPress={buttonPress} title="Default" size="sm" />
113
+ <Button onPress={buttonPress} title="Default" size="md" />
114
+ <Button onPress={buttonPress} title="Danger" appearance="danger" size="lg" />
115
+ </Row>
116
+ <Row>
117
+ <Button disabled onPress={buttonPress} title="Disabled" size="sm" />
118
+ <Button disabled onPress={buttonPress} title="Disabled" size="md" />
119
+ <Button disabled onPress={buttonPress} title="Disabled" appearance="danger" size="lg" />
120
+ </Row>
121
+ <Row>
122
+ <Button
123
+ onPress={buttonPress}
124
+ title="Default"
125
+ size="sm"
126
+ iconNameLeft="general.plus"
127
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
128
+ />
129
+ <Button
130
+ onPress={buttonPress}
131
+ title="Default"
132
+ size="md"
133
+ iconNameRight="churchCenter.sort"
134
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
135
+ />
136
+ <Button
137
+ onPress={buttonPress}
138
+ title="Danger"
139
+ appearance="danger"
140
+ size="lg"
141
+ iconNameLeft="groups.cards"
142
+ iconNameRight="general.downChevron"
143
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
144
+ />
145
+ </Row>
146
+ <Row>
147
+ <Button loading onPress={buttonPress} title="Default" size="sm" />
148
+ <Button loading onPress={buttonPress} title="Default" size="md" />
149
+ <Button loading onPress={buttonPress} title="Danger" appearance="danger" size="lg" />
150
+ </Row>
151
+ <Row>
152
+ <Button onPress={buttonPress} title="Default" size="sm" variant="outline" />
153
+ <Button onPress={buttonPress} title="Default" size="md" variant="outline" />
154
+ <Button
155
+ onPress={buttonPress}
156
+ title="Danger"
157
+ appearance="danger"
158
+ size="lg"
159
+ variant="outline"
160
+ />
161
+ </Row>
162
+ <Row>
163
+ <Button
164
+ onPress={buttonPress}
165
+ title="Default"
166
+ size="sm"
167
+ variant="outline"
168
+ iconNameLeft="general.plus"
169
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
170
+ />
171
+ <Button
172
+ onPress={buttonPress}
173
+ title="Default"
174
+ size="md"
175
+ variant="outline"
176
+ iconNameRight="churchCenter.sort"
177
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
178
+ />
179
+ <Button
180
+ onPress={buttonPress}
181
+ title="Danger"
182
+ appearance="danger"
183
+ size="lg"
184
+ variant="outline"
185
+ iconNameLeft="groups.cards"
186
+ iconNameRight="general.downChevron"
187
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
188
+ />
189
+ </Row>
190
+ <Row>
191
+ <Button
192
+ disabled
193
+ onPress={buttonPress}
194
+ title="Disabled"
195
+ size="sm"
196
+ variant="outline"
197
+ iconNameLeft="general.plus"
198
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
199
+ />
200
+ <Button
201
+ disabled
202
+ onPress={buttonPress}
203
+ title="Disabled"
204
+ size="md"
205
+ variant="outline"
206
+ iconNameRight="churchCenter.sort"
207
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
208
+ />
209
+ <Button
210
+ disabled
211
+ onPress={buttonPress}
212
+ title="Disabled"
213
+ appearance="danger"
214
+ size="lg"
215
+ variant="outline"
216
+ iconNameLeft="groups.cards"
217
+ iconNameRight="general.downChevron"
218
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
219
+ />
220
+ </Row>
221
+ <Row>
222
+ <Button
223
+ loading
224
+ onPress={buttonPress}
225
+ title="Default"
226
+ size="sm"
227
+ variant="outline"
228
+ iconNameLeft="general.plus"
229
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
230
+ />
231
+ <Button
232
+ loading
233
+ onPress={buttonPress}
234
+ title="Default"
235
+ size="md"
236
+ variant="outline"
237
+ iconNameRight="churchCenter.sort"
238
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
239
+ />
240
+ <Button
241
+ loading
242
+ onPress={buttonPress}
243
+ title="Danger"
244
+ appearance="danger"
245
+ size="lg"
246
+ variant="outline"
247
+ iconNameLeft="groups.cards"
248
+ iconNameRight="general.downChevron"
249
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
250
+ />
251
+ </Row>
252
+ </Group>
253
+ <Group
254
+ title="TextButton"
255
+ description="Pressable text with default & danger appearance options. Can be disabled and accept `Text` variance props."
256
+ >
257
+ <Row>
258
+ <TextButton onPress={buttonPress}>Default</TextButton>
259
+ <TextButton onPress={buttonPress} variant="secondary">
260
+ Default
261
+ </TextButton>
262
+ <TextButton onPress={buttonPress} variant="tertiary">
263
+ Default
264
+ </TextButton>
265
+ <TextButton onPress={buttonPress} variant="footnote">
266
+ Default
267
+ </TextButton>
268
+ </Row>
269
+ <Row>
270
+ <TextButton onPress={buttonPress} appearance="danger">
271
+ Danger
272
+ </TextButton>
273
+ <TextButton onPress={buttonPress} variant="secondary" appearance="danger">
274
+ Danger
275
+ </TextButton>
276
+ <TextButton onPress={buttonPress} variant="tertiary" appearance="danger">
277
+ Danger
278
+ </TextButton>
279
+ <TextButton onPress={buttonPress} variant="footnote" appearance="danger">
280
+ Danger
281
+ </TextButton>
282
+ </Row>
283
+ <Row>
284
+ <TextButton onPress={buttonPress} disabled>
285
+ Disabled
286
+ </TextButton>
287
+ <TextButton onPress={buttonPress} variant="secondary" disabled>
288
+ Disabled
289
+ </TextButton>
290
+ <TextButton onPress={buttonPress} variant="tertiary" disabled>
291
+ Disabled
292
+ </TextButton>
293
+ <TextButton onPress={buttonPress} variant="footnote" disabled>
294
+ Disabled
295
+ </TextButton>
296
+ </Row>
297
+ </Group>
298
+ <Group
299
+ title="TextInlineButton"
300
+ description="Supports nesting within `Text`. Temporary component until React Native fixes a layout bug in `Pressable` which used in `TextButton`."
301
+ >
302
+ <Row style={styles.alignRowLeft}>
303
+ <Text>
304
+ This text is next to{' '}
305
+ <TextInlineButton onPress={buttonPress}>default button text</TextInlineButton> Lorem
306
+ ipsum dolor{' '}
307
+ <TextInlineButton onPress={buttonPress} appearance="danger">
308
+ danger button text
309
+ </TextInlineButton>{' '}
310
+ consectetur{' '}
311
+ <TextInlineButton onPress={buttonPress} disabled>
312
+ disabled button text
313
+ </TextInlineButton>{' '}
314
+ elit.
315
+ </Text>
316
+ <Text variant="secondary">
317
+ This text is next to{' '}
318
+ <TextInlineButton variant="secondary" onPress={buttonPress}>
319
+ default button text
320
+ </TextInlineButton>{' '}
321
+ Lorem ipsum dolor{' '}
322
+ <TextInlineButton variant="secondary" onPress={buttonPress} appearance="danger">
323
+ danger button text
324
+ </TextInlineButton>{' '}
325
+ consectetur{' '}
326
+ <TextInlineButton variant="secondary" onPress={buttonPress} disabled>
327
+ disabled button text
328
+ </TextInlineButton>{' '}
329
+ elit.
330
+ </Text>
331
+ <Text variant="tertiary">
332
+ This text is next to{' '}
333
+ <TextInlineButton variant="tertiary" onPress={buttonPress}>
334
+ default button text
335
+ </TextInlineButton>{' '}
336
+ Lorem ipsum dolor{' '}
337
+ <TextInlineButton variant="tertiary" onPress={buttonPress} appearance="danger">
338
+ danger button text
339
+ </TextInlineButton>{' '}
340
+ consectetur{' '}
341
+ <TextInlineButton variant="tertiary" onPress={buttonPress} disabled>
342
+ disabled button text
343
+ </TextInlineButton>{' '}
344
+ elit.
345
+ </Text>
346
+ <Text variant="footnote">
347
+ This text is next to{' '}
348
+ <TextInlineButton variant="footnote" onPress={buttonPress}>
349
+ default button text
350
+ </TextInlineButton>{' '}
351
+ Lorem ipsum dolor{' '}
352
+ <TextInlineButton variant="footnote" onPress={buttonPress} appearance="danger">
353
+ danger button text
354
+ </TextInlineButton>{' '}
355
+ consectetur{' '}
356
+ <TextInlineButton variant="footnote" onPress={buttonPress} disabled>
357
+ disabled button text
358
+ </TextInlineButton>{' '}
359
+ elit.
360
+ </Text>
361
+ </Row>
362
+ </Group>
363
+ <Group
364
+ title="Heading"
365
+ description="Use for headings & titles as it includes the a11y 'header' role. Change the size and style with the h1-h4 variants."
366
+ >
367
+ <Row>
368
+ <Heading>Heading 1</Heading>
369
+ <Heading variant="h2">Heading 2</Heading>
370
+ <Heading variant="h3">Heading 3</Heading>
371
+ <Heading variant="h4">Heading 4</Heading>
372
+ </Row>
373
+ </Group>
374
+ <Group title="Text" description="Use for body copy and supporting text.">
375
+ <Row>
376
+ <Text>Plain text</Text>
377
+ <Text variant="secondary">Secondary</Text>
378
+ <Text variant="tertiary">Tertiary</Text>
379
+ <Text variant="footnote">Footnote</Text>
380
+ </Row>
381
+ </Group>
382
+ </CollapsableSection>
75
383
  </ScrollView>
76
384
  )
77
385
  }
78
386
 
387
+ interface CollapsableSectionProps {
388
+ children: React.ReactNode
389
+ title: string
390
+ isLast?: boolean
391
+ }
392
+
393
+ function CollapsableSection({ children, title, isLast = false }: CollapsableSectionProps) {
394
+ const styles = useStyles()
395
+ const { colors } = useTheme()
396
+ const [collapsed, setCollapsed] = useState(true)
397
+
398
+ return (
399
+ <View style={[styles.section, styles.sectionBorderTop, isLast && styles.sectionBorderBottom]}>
400
+ <Pressable
401
+ onPress={() => setCollapsed(!collapsed)}
402
+ style={({ pressed }) => [styles.sectionHeader, pressed && platformPressedOpacityStyle]}
403
+ android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}
404
+ >
405
+ <Heading>{title}</Heading>
406
+ <Icon name={collapsed ? 'general.plus' : 'general.minus'} size={16} />
407
+ </Pressable>
408
+ {!collapsed && <View style={styles.sectionChildren}>{children}</View>}
409
+ </View>
410
+ )
411
+ }
412
+
413
+ interface GroupProps {
414
+ title: string
415
+ description?: string
416
+ children: React.ReactNode
417
+ }
418
+
419
+ function Group({ title, description, children }: GroupProps) {
420
+ const styles = useStyles()
421
+ return (
422
+ <View style={styles.group}>
423
+ <View style={styles.groupHeading}>
424
+ <Heading variant="h3">{title}</Heading>
425
+ {description && <Text variant="footnote">{description}</Text>}
426
+ </View>
427
+ {children}
428
+ </View>
429
+ )
430
+ }
431
+
432
+ interface RowProps {
433
+ children: React.ReactNode
434
+ style?: ViewStyle
435
+ }
436
+
437
+ function Row({ children, style }: RowProps) {
438
+ const styles = useStyles()
439
+ return <View style={[styles.row, style]}>{children}</View>
440
+ }
441
+
79
442
  const useStyles = () => {
80
443
  const { colors } = useTheme()
81
444
 
82
445
  return StyleSheet.create({
83
- scrollView: { flex: 1, backgroundColor: colors.fillColorNeutral100Inverted },
84
- container: { gap: space(2), padding: space(3) },
446
+ scrollView: {
447
+ flex: 1,
448
+ backgroundColor: colors.fillColorNeutral100Inverted,
449
+ },
450
+ container: {
451
+ padding: space(3),
452
+ },
85
453
  listItem: { color: colors.fillColorNeutral020 },
454
+ section: {
455
+ gap: space(1),
456
+ borderColor: colors.fillColorNeutral020,
457
+ },
458
+ sectionBorderTop: {
459
+ borderTopWidth: 1,
460
+ },
461
+ sectionBorderBottom: {
462
+ borderBottomWidth: 1,
463
+ },
464
+ sectionHeader: {
465
+ flexDirection: 'row',
466
+ justifyContent: 'space-between',
467
+ alignItems: 'center',
468
+ paddingVertical: space(3),
469
+ },
470
+ sectionChildren: {
471
+ paddingBottom: space(3),
472
+ gap: space(6),
473
+ },
86
474
  row: {
87
475
  gap: space(2),
88
476
  flexDirection: 'row',
@@ -90,7 +478,15 @@ const useStyles = () => {
90
478
  justifyContent: 'center',
91
479
  flexWrap: 'wrap',
92
480
  },
93
- column: { gap: space(4) },
481
+ alignRowLeft: {
482
+ justifyContent: 'flex-start',
483
+ },
484
+ group: {
485
+ gap: space(3),
486
+ },
487
+ groupHeading: {
488
+ gap: space(1),
489
+ },
94
490
  spinnerContainer: {
95
491
  height: space(2.5),
96
492
  },
@@ -6,7 +6,7 @@ export function NotFound() {
6
6
  return (
7
7
  <View style={styles.container}>
8
8
  <Text>404</Text>
9
- <Button screen="Conversations">Go to Home</Button>
9
+ <Button href="Conversations">Go to Home</Button>
10
10
  </View>
11
11
  )
12
12
  }
@@ -0,0 +1,24 @@
1
+ export interface ResourceObject {
2
+ id: string
3
+ type: string
4
+ }
5
+
6
+ export type ApiResource<Type = ResourceObject> = {
7
+ data: Type
8
+ links: Record<string, string>
9
+ meta: Record<string, unknown>
10
+ }
11
+
12
+ export type ApiCollection<Type = ResourceObject> = {
13
+ data: Type[]
14
+ links: Record<string, string>
15
+ meta: CollectionMeta
16
+ }
17
+
18
+ interface CollectionMeta {
19
+ count: number
20
+ totalCount: number
21
+ next?: Record<string, unknown>
22
+ parent?: ResourceObject
23
+ [attributeName: string]: unknown
24
+ }
@@ -0,0 +1,3 @@
1
+ export * from './api_primitives'
2
+ export * from './resources'
3
+ export * from './utils'