@planningcenter/chat-react-native 2.1.1 → 2.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/build/components/conversation/message_form.d.ts.map +1 -1
  2. package/build/components/conversation/message_form.js +4 -4
  3. package/build/components/conversation/message_form.js.map +1 -1
  4. package/build/components/display/badge.d.ts +2 -9
  5. package/build/components/display/badge.d.ts.map +1 -1
  6. package/build/components/display/badge.js +8 -40
  7. package/build/components/display/badge.js.map +1 -1
  8. package/build/components/display/banner.d.ts +29 -0
  9. package/build/components/display/banner.d.ts.map +1 -0
  10. package/build/components/display/banner.js +16 -0
  11. package/build/components/display/banner.js.map +1 -0
  12. package/build/components/display/button.d.ts +1 -1
  13. package/build/components/display/button.d.ts.map +1 -1
  14. package/build/components/display/button.js +1 -1
  15. package/build/components/display/button.js.map +1 -1
  16. package/build/components/display/icon_button.d.ts +1 -1
  17. package/build/components/display/icon_button.d.ts.map +1 -1
  18. package/build/components/display/icon_button.js +1 -1
  19. package/build/components/display/icon_button.js.map +1 -1
  20. package/build/components/display/index.d.ts +1 -0
  21. package/build/components/display/index.d.ts.map +1 -1
  22. package/build/components/display/index.js +1 -0
  23. package/build/components/display/index.js.map +1 -1
  24. package/build/components/display/text_button.d.ts +1 -1
  25. package/build/components/display/text_button.d.ts.map +1 -1
  26. package/build/components/display/text_button.js +1 -1
  27. package/build/components/display/text_button.js.map +1 -1
  28. package/build/components/display/text_inline_button.d.ts +2 -2
  29. package/build/components/display/text_inline_button.d.ts.map +1 -1
  30. package/build/components/display/text_inline_button.js +3 -2
  31. package/build/components/display/text_inline_button.js.map +1 -1
  32. package/build/components/display/{button_color_utils.d.ts → utils/button_colors.d.ts} +1 -1
  33. package/build/components/display/utils/button_colors.d.ts.map +1 -0
  34. package/build/components/display/{button_color_utils.js → utils/button_colors.js} +2 -2
  35. package/build/components/display/utils/button_colors.js.map +1 -0
  36. package/build/components/display/utils/status_colors.d.ts +17 -0
  37. package/build/components/display/utils/status_colors.d.ts.map +1 -0
  38. package/build/components/display/utils/status_colors.js +49 -0
  39. package/build/components/display/utils/status_colors.js.map +1 -0
  40. package/build/components/primitive/banner_primitive.d.ts +38 -0
  41. package/build/components/primitive/banner_primitive.d.ts.map +1 -0
  42. package/build/components/primitive/banner_primitive.js +112 -0
  43. package/build/components/primitive/banner_primitive.js.map +1 -0
  44. package/build/contexts/api_provider.js +4 -3
  45. package/build/contexts/api_provider.js.map +1 -1
  46. package/build/contexts/chat_context.d.ts +2 -2
  47. package/build/contexts/chat_context.d.ts.map +1 -1
  48. package/build/contexts/chat_context.js +3 -15
  49. package/build/contexts/chat_context.js.map +1 -1
  50. package/build/hooks/use_api_client.d.ts +6 -0
  51. package/build/hooks/use_api_client.d.ts.map +1 -0
  52. package/build/hooks/use_api_client.js +18 -0
  53. package/build/hooks/use_api_client.js.map +1 -0
  54. package/build/hooks/use_conversation.d.ts +122 -0
  55. package/build/hooks/use_conversation.d.ts.map +1 -0
  56. package/build/hooks/use_conversation.js +103 -0
  57. package/build/hooks/use_conversation.js.map +1 -0
  58. package/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
  59. package/build/hooks/use_conversation_jolt_events.js +3 -4
  60. package/build/hooks/use_conversation_jolt_events.js.map +1 -1
  61. package/build/hooks/use_font_scale.d.ts +1 -1
  62. package/build/hooks/use_font_scale.d.ts.map +1 -1
  63. package/build/hooks/use_font_scale.js +1 -1
  64. package/build/hooks/use_font_scale.js.map +1 -1
  65. package/build/hooks/use_jolt.d.ts +1 -1
  66. package/build/hooks/use_jolt.d.ts.map +1 -1
  67. package/build/hooks/use_jolt.js +6 -6
  68. package/build/hooks/use_jolt.js.map +1 -1
  69. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  70. package/build/hooks/use_suspense_api.js +3 -4
  71. package/build/hooks/use_suspense_api.js.map +1 -1
  72. package/build/navigation/header.d.ts +10 -0
  73. package/build/navigation/header.d.ts.map +1 -0
  74. package/build/navigation/header.js +16 -0
  75. package/build/navigation/header.js.map +1 -0
  76. package/build/navigation/index.d.ts +17 -4
  77. package/build/navigation/index.d.ts.map +1 -1
  78. package/build/navigation/index.js +18 -6
  79. package/build/navigation/index.js.map +1 -1
  80. package/build/screens/conversation_details_screen.d.ts +7 -0
  81. package/build/screens/conversation_details_screen.d.ts.map +1 -0
  82. package/build/screens/conversation_details_screen.js +155 -0
  83. package/build/screens/conversation_details_screen.js.map +1 -0
  84. package/build/screens/conversation_screen.d.ts +5 -3
  85. package/build/screens/conversation_screen.d.ts.map +1 -1
  86. package/build/screens/conversation_screen.js +43 -15
  87. package/build/screens/conversation_screen.js.map +1 -1
  88. package/build/screens/design_system_screen.d.ts.map +1 -1
  89. package/build/screens/design_system_screen.js +24 -1
  90. package/build/screens/design_system_screen.js.map +1 -1
  91. package/build/screens/message_actions_screen.d.ts.map +1 -1
  92. package/build/screens/message_actions_screen.js +7 -7
  93. package/build/screens/message_actions_screen.js.map +1 -1
  94. package/build/utils/client/request_helpers.d.ts +2 -1
  95. package/build/utils/client/request_helpers.d.ts.map +1 -1
  96. package/build/utils/client/request_helpers.js +17 -0
  97. package/build/utils/client/request_helpers.js.map +1 -1
  98. package/package.json +2 -2
  99. package/src/components/conversation/message_form.tsx +4 -4
  100. package/src/components/display/badge.tsx +9 -53
  101. package/src/components/display/banner.tsx +56 -0
  102. package/src/components/display/button.tsx +2 -2
  103. package/src/components/display/icon_button.tsx +2 -2
  104. package/src/components/display/index.ts +1 -0
  105. package/src/components/display/text_button.tsx +2 -2
  106. package/src/components/display/text_inline_button.tsx +4 -2
  107. package/src/components/display/{button_color_utils.ts → utils/button_colors.ts} +1 -1
  108. package/src/components/display/utils/status_colors.ts +85 -0
  109. package/src/components/primitive/banner_primitive.tsx +247 -0
  110. package/src/contexts/api_provider.tsx +5 -5
  111. package/src/contexts/chat_context.tsx +4 -21
  112. package/src/hooks/use_api_client.ts +29 -0
  113. package/src/hooks/use_conversation.ts +113 -0
  114. package/src/hooks/use_conversation_jolt_events.ts +3 -4
  115. package/src/hooks/use_font_scale.ts +3 -1
  116. package/src/hooks/use_jolt.ts +9 -9
  117. package/src/hooks/use_suspense_api.ts +3 -4
  118. package/src/navigation/header.tsx +24 -0
  119. package/src/navigation/index.tsx +20 -6
  120. package/src/screens/conversation_details_screen.tsx +205 -0
  121. package/src/screens/conversation_screen.tsx +65 -20
  122. package/src/screens/design_system_screen.tsx +56 -0
  123. package/src/screens/message_actions_screen.tsx +7 -7
  124. package/src/utils/client/request_helpers.ts +21 -1
  125. package/build/components/display/button_color_utils.d.ts.map +0 -1
  126. package/build/components/display/button_color_utils.js.map +0 -1
@@ -7,30 +7,12 @@ import { Icon } from './icon'
7
7
  import { Text } from './text'
8
8
  import { platformFontWeightMedium, space } from '../../utils'
9
9
  import { tokens } from '../../vendor/tapestry/tokens'
10
+ import { useStatusColorAppearanceMap, type StatusAppearanceUnion } from './utils/status_colors'
10
11
 
11
12
  // =================================
12
13
  // ====== Constants ================
13
14
  // =================================
14
15
 
15
- const APPEARANCES = {
16
- error: 'error',
17
- info: 'info',
18
- neutral: 'neutral',
19
- success: 'success',
20
- warning: 'warning',
21
- } as const
22
-
23
- type AppearanceUnion = (typeof APPEARANCES)[keyof typeof APPEARANCES]
24
-
25
- type AppearanceColors = Record<
26
- AppearanceUnion,
27
- {
28
- background: string
29
- text: string
30
- icon: string
31
- }
32
- >
33
-
34
16
  const VARIANTS = {
35
17
  default: 'default',
36
18
  meta: 'meta',
@@ -77,7 +59,7 @@ interface BadgeProps {
77
59
  /**
78
60
  * Changes the status color for the badge and icon.
79
61
  */
80
- appearance?: AppearanceUnion
62
+ appearance?: StatusAppearanceUnion
81
63
  /**
82
64
  * Changes form of the logo to support a meta label and badge
83
65
  */
@@ -151,33 +133,7 @@ const useStyles = ({
151
133
  const { colors } = useTheme()
152
134
  const fontScale = useFontScale({ maxFontSizeMultiplier })
153
135
 
154
- const apparenceColorMap: AppearanceColors = {
155
- error: {
156
- background: colors.statusErrorBackground,
157
- text: colors.statusErrorText,
158
- icon: colors.statusErrorIcon,
159
- },
160
- info: {
161
- background: colors.statusInfoBackground,
162
- text: colors.statusInfoText,
163
- icon: colors.statusInfoIcon,
164
- },
165
- neutral: {
166
- background: colors.statusNeutralBackground,
167
- text: colors.statusNeutralText,
168
- icon: colors.statusNeutralIcon,
169
- },
170
- success: {
171
- background: colors.statusSuccessBackground,
172
- text: colors.statusSuccessText,
173
- icon: colors.statusSuccessIcon,
174
- },
175
- warning: {
176
- background: colors.statusWarningBackground,
177
- text: colors.statusWarningText,
178
- icon: colors.statusWarningIcon,
179
- },
180
- }
136
+ const statusColorMap = useStatusColorAppearanceMap()
181
137
 
182
138
  const badgePaddingHorizontal = space(1) * fontScale
183
139
  const badgePaddingVertical = space(0.5) * fontScale
@@ -187,24 +143,24 @@ const useStyles = ({
187
143
  const variantStylesMap: VariantStyles = {
188
144
  default: {
189
145
  gap: badgeGap,
190
- backgroundColor: apparenceColorMap[appearance].background,
146
+ backgroundColor: statusColorMap[appearance].background,
191
147
  metaLabelPaddingLeft: badgePaddingHorizontal,
192
148
  paddingHorizontal: badgePaddingHorizontal,
193
149
  paddingVertical: badgePaddingVertical,
194
150
  borderWidth: tokens.borderSizeDefault * fontScale,
195
151
  borderRadius: tokens.borderRadiusMd,
196
- textColor: apparenceColorMap[appearance].text,
152
+ textColor: statusColorMap[appearance].text,
197
153
  fontWeight: 'normal',
198
154
  },
199
155
  meta: {
200
156
  gap: badgeGap,
201
- backgroundColor: apparenceColorMap[appearance].background,
157
+ backgroundColor: statusColorMap[appearance].background,
202
158
  metaLabelPaddingLeft: badgePaddingHorizontal,
203
159
  paddingHorizontal: badgePaddingHorizontal,
204
160
  paddingVertical: badgePaddingVertical,
205
161
  borderWidth: tokens.borderSizeDefault * fontScale,
206
162
  borderRadius: tokens.borderRadiusMd,
207
- textColor: apparenceColorMap[appearance].text,
163
+ textColor: statusColorMap[appearance].text,
208
164
  fontWeight: platformFontWeightMedium,
209
165
  },
210
166
  metaSubtle: {
@@ -227,7 +183,7 @@ const useStyles = ({
227
183
  justifyContent: 'center',
228
184
  borderRadius: variantStylesMap[variant].borderRadius,
229
185
  borderWidth: variantStylesMap[variant].borderWidth,
230
- borderColor: apparenceColorMap[appearance].background,
186
+ borderColor: statusColorMap[appearance].background,
231
187
  },
232
188
  badge: {
233
189
  flexDirection: 'row',
@@ -239,7 +195,7 @@ const useStyles = ({
239
195
  borderRadius: variantStylesMap[variant].borderRadius - 2,
240
196
  },
241
197
  icon: {
242
- color: apparenceColorMap[appearance].icon,
198
+ color: statusColorMap[appearance].icon,
243
199
  fontSize: badgeFontSize,
244
200
  },
245
201
  logo: {
@@ -0,0 +1,56 @@
1
+ import React, { isValidElement, ReactElement } from 'react'
2
+ import BannerPrimitive, {
3
+ type BannerStatusIconProps,
4
+ type BannerRootProps,
5
+ } from '../primitive/banner_primitive'
6
+
7
+ interface BannerProps {
8
+ /**
9
+ * Changes the status color for the background, text, and icon.
10
+ * Sets a preset status icon.
11
+ */
12
+ appearance?: BannerRootProps['appearance']
13
+ /**
14
+ * Renders the banner's main text.
15
+ * If some of the text is interactive it can also take `BannerPrimitive.Link` wrapped in `BannerPrimitive.Text`.
16
+ */
17
+ description: string | ReactElement
18
+ /**
19
+ * Renders the banner's heading text.
20
+ */
21
+ heading?: string
22
+ /**
23
+ * Overrides the preset status icon.
24
+ */
25
+ iconName?: BannerStatusIconProps['iconName']
26
+ /**
27
+ * Hides the status icon. By default, the status icon is shown.
28
+ */
29
+ showIcon?: boolean
30
+ }
31
+
32
+ export function Banner({
33
+ appearance,
34
+ description,
35
+ heading,
36
+ iconName,
37
+ showIcon = true,
38
+ }: BannerProps) {
39
+ if (!description && !heading) return null
40
+
41
+ return (
42
+ <BannerPrimitive.Root appearance={appearance}>
43
+ <BannerPrimitive.StaticLayout>
44
+ {showIcon && <BannerPrimitive.StatusIcon iconName={iconName} />}
45
+ <BannerPrimitive.Content>
46
+ {Boolean(heading) && <BannerPrimitive.Heading>{heading}</BannerPrimitive.Heading>}
47
+ {isValidElement(description) ? (
48
+ description
49
+ ) : (
50
+ <BannerPrimitive.Text>{description}</BannerPrimitive.Text>
51
+ )}
52
+ </BannerPrimitive.Content>
53
+ </BannerPrimitive.StaticLayout>
54
+ </BannerPrimitive.Root>
55
+ )
56
+ }
@@ -7,8 +7,8 @@ import { useTheme, useFontScale, useCreateAndroidRippleColor } from '../../hooks
7
7
  import { tokens } from '../../vendor/tapestry/tokens'
8
8
  import { platformFontWeightBold, platformPressedOpacityStyle } from '../../utils'
9
9
  import { Spinner } from './spinner'
10
- import { getColorKey, useButtonColorOptionMap, useGradientColorMap } from './button_color_utils'
11
- import type { ButtonAppearanceUnion } from './button_color_utils'
10
+ import { getColorKey, useButtonColorOptionMap, useGradientColorMap } from './utils/button_colors'
11
+ import type { ButtonAppearanceUnion } from './utils/button_colors'
12
12
 
13
13
  // =================================
14
14
  // ====== Constants ================
@@ -6,8 +6,8 @@ import type { IconProps } from './icon'
6
6
  import { useTheme, useFontScale, useCreateAndroidRippleColor } from '../../hooks'
7
7
  import { platformPressedOpacityStyle } from '../../utils'
8
8
  import { Spinner } from './spinner'
9
- import { getColorKey, useIconButtonColorOptionMap } from './button_color_utils'
10
- import type { IconButtonAppearanceUnion } from './button_color_utils'
9
+ import { getColorKey, useIconButtonColorOptionMap } from './utils/button_colors'
10
+ import type { IconButtonAppearanceUnion } from './utils/button_colors'
11
11
 
12
12
  // =================================
13
13
  // ====== Constants ================
@@ -1,6 +1,7 @@
1
1
  export * from './avatar'
2
2
  export * from './avatar_group'
3
3
  export * from './badge'
4
+ export * from './banner'
4
5
  export * from './button'
5
6
  export * from './heading'
6
7
  export * from './icon'
@@ -5,8 +5,8 @@ import { useTheme } from '../../hooks'
5
5
  import { platformFontWeightMedium } from '../../utils'
6
6
  import { Text } from './text'
7
7
  import type { TextProps } from './text'
8
- import { getColorKey, useButtonColorOptionMap } from './button_color_utils'
9
- import type { ButtonAppearanceUnion } from './button_color_utils'
8
+ import { getColorKey, useButtonColorOptionMap } from './utils/button_colors'
9
+ import type { ButtonAppearanceUnion } from './utils/button_colors'
10
10
 
11
11
  // =================================
12
12
  // ====== Component ================
@@ -5,8 +5,8 @@ import { Text } from './text'
5
5
  import type { TextProps } from './text'
6
6
  import { platformFontWeightMedium } from '../../utils'
7
7
  import colorFunction from 'color'
8
- import { getColorKey, useButtonColorOptionMap } from './button_color_utils'
9
- import type { ButtonAppearanceUnion } from './button_color_utils'
8
+ import { getColorKey, useButtonColorOptionMap } from './utils/button_colors'
9
+ import type { ButtonAppearanceUnion } from './utils/button_colors'
10
10
 
11
11
  // =================================
12
12
  // ====== Component ================
@@ -24,6 +24,7 @@ export function TextInlineButton({
24
24
  children,
25
25
  disabled = false,
26
26
  onPress,
27
+ style,
27
28
  ...props
28
29
  }: TextInlineButtonProps) {
29
30
  const styles = useStyles({ appearance, disabled })
@@ -43,6 +44,7 @@ export function TextInlineButton({
43
44
  styles.underline,
44
45
  disabled && styles.disabled,
45
46
  isPressed && platformPressedStyle,
47
+ style,
46
48
  ]}
47
49
  onPress={!disabled ? onPress : undefined}
48
50
  onPressIn={() => setIsPressed(true)}
@@ -1,4 +1,4 @@
1
- import { useTheme } from '../../hooks'
1
+ import { useTheme } from '../../../hooks'
2
2
 
3
3
  // =================================
4
4
  // ====== Exports ==================
@@ -0,0 +1,85 @@
1
+ import { useTheme } from '../../../hooks'
2
+
3
+ // =================================
4
+ // ====== Exports ==================
5
+ // =================================
6
+
7
+ export { useStatusColorAppearanceMap }
8
+ export type { StatusAppearanceUnion }
9
+
10
+ // =================================
11
+ // ====== Constants ================
12
+ // =================================
13
+
14
+ const STATUS_APPEARANCES = {
15
+ error: 'error',
16
+ info: 'info',
17
+ neutral: 'neutral',
18
+ success: 'success',
19
+ warning: 'warning',
20
+ } as const
21
+
22
+ type StatusAppearanceUnion = (typeof STATUS_APPEARANCES)[keyof typeof STATUS_APPEARANCES]
23
+
24
+ type StatusAppearanceColors = Record<
25
+ StatusAppearanceUnion,
26
+ {
27
+ background: string
28
+ text: string
29
+ icon: string
30
+ }
31
+ >
32
+
33
+ // =================================
34
+ // ====== Hooks ====================
35
+ // =================================
36
+
37
+ function useStatusColorAppearanceMap(): StatusAppearanceColors {
38
+ const {
39
+ colors: {
40
+ statusErrorBackground,
41
+ statusErrorText,
42
+ statusErrorIcon,
43
+ statusInfoBackground,
44
+ statusInfoText,
45
+ statusInfoIcon,
46
+ statusNeutralBackground,
47
+ statusNeutralText,
48
+ statusNeutralIcon,
49
+ statusSuccessBackground,
50
+ statusSuccessText,
51
+ statusSuccessIcon,
52
+ statusWarningBackground,
53
+ statusWarningText,
54
+ statusWarningIcon,
55
+ },
56
+ } = useTheme()
57
+
58
+ return {
59
+ error: {
60
+ background: statusErrorBackground,
61
+ text: statusErrorText,
62
+ icon: statusErrorIcon,
63
+ },
64
+ info: {
65
+ background: statusInfoBackground,
66
+ text: statusInfoText,
67
+ icon: statusInfoIcon,
68
+ },
69
+ neutral: {
70
+ background: statusNeutralBackground,
71
+ text: statusNeutralText,
72
+ icon: statusNeutralIcon,
73
+ },
74
+ success: {
75
+ background: statusSuccessBackground,
76
+ text: statusSuccessText,
77
+ icon: statusSuccessIcon,
78
+ },
79
+ warning: {
80
+ background: statusWarningBackground,
81
+ text: statusWarningText,
82
+ icon: statusWarningIcon,
83
+ },
84
+ }
85
+ }
@@ -0,0 +1,247 @@
1
+ import React, { createContext, FC, ReactNode, useContext } from 'react'
2
+ import { StyleSheet, View } from 'react-native'
3
+ import {
4
+ useStatusColorAppearanceMap,
5
+ type StatusAppearanceUnion,
6
+ } from '../display/utils/status_colors'
7
+ import { MAX_FONT_SIZE_MULTIPLIER, platformFontWeightMedium, space } from '../../utils'
8
+ import { tokens } from '../../vendor/tapestry/tokens'
9
+ import { Heading, Icon, Text, TextInlineButton } from '../display'
10
+ import { useFontScale } from '../../hooks'
11
+
12
+ // ========================================
13
+ // ====== Exports =========================
14
+ // ========================================
15
+
16
+ const Banner = {
17
+ Root: BannerRoot,
18
+ StaticLayout: BannerStaticLayout,
19
+ Content: BannerContent,
20
+ StatusIcon: BannerStatusIcon,
21
+ Heading: BannerHeading,
22
+ Text: BannerText,
23
+ Link: BannerLink,
24
+ } as const
25
+
26
+ type BannerComponents = {
27
+ Root: FC<BannerRootProps>
28
+ StaticLayout: FC<BannerStaticLayoutProps>
29
+ Content: FC<BannerContentProps>
30
+ StatusIcon: FC<BannerStatusIconProps>
31
+ Heading: FC<BannerHeadingProps>
32
+ Text: FC<BannerTextProps>
33
+ Link: FC<BannerLinkProps>
34
+ }
35
+
36
+ export default Banner as BannerComponents
37
+ export type {
38
+ BannerRootProps,
39
+ BannerStaticLayoutProps,
40
+ BannerContentProps,
41
+ BannerStatusIconProps,
42
+ BannerHeadingProps,
43
+ BannerTextProps,
44
+ BannerLinkProps,
45
+ }
46
+
47
+ // ========================================
48
+ // ====== Context =========================
49
+ // ========================================
50
+
51
+ interface BannerContextType {
52
+ appearance?: StatusAppearanceUnion
53
+ }
54
+
55
+ const BannerContext = createContext<BannerContextType | null>(null)
56
+
57
+ function useBannerContext() {
58
+ const context = useContext(BannerContext)
59
+ if (!context) {
60
+ throw new Error('Banner components must be used within Banner.Root')
61
+ }
62
+ return context
63
+ }
64
+
65
+ // ========================================
66
+ // ====== BannerRoot ======================
67
+ // ========================================
68
+
69
+ interface BannerRootProps {
70
+ children: ReactNode
71
+ appearance?: StatusAppearanceUnion
72
+ }
73
+
74
+ function BannerRoot({ children, appearance = 'neutral' }: BannerRootProps) {
75
+ return <BannerContext.Provider value={{ appearance }}>{children}</BannerContext.Provider>
76
+ }
77
+
78
+ BannerRoot.displayName = 'Banner.Root'
79
+
80
+ // ========================================
81
+ // ====== BannerStaticLayout ==============
82
+ // ========================================
83
+
84
+ interface BannerStaticLayoutProps {
85
+ children: ReactNode
86
+ }
87
+
88
+ function BannerStaticLayout({ children }: BannerStaticLayoutProps) {
89
+ const { appearance } = useBannerContext()
90
+ const styles = useStyles({ appearance })
91
+
92
+ return <View style={styles.staticLayout}>{children}</View>
93
+ }
94
+
95
+ BannerStaticLayout.displayName = 'Banner.StaticLayout'
96
+
97
+ // ========================================
98
+ // ====== BannerContent ===================
99
+ // ========================================
100
+
101
+ interface BannerContentProps {
102
+ children: ReactNode
103
+ }
104
+
105
+ function BannerContent({ children }: BannerContentProps) {
106
+ const styles = useStyles()
107
+
108
+ return <View style={styles.content}>{children}</View>
109
+ }
110
+
111
+ BannerContent.displayName = 'Banner.Content'
112
+
113
+ // ========================================
114
+ // ====== BannerStatusIcon ================
115
+ // ========================================
116
+
117
+ interface BannerStatusIconProps {
118
+ iconName?: string
119
+ }
120
+
121
+ function BannerStatusIcon({ iconName }: BannerStatusIconProps) {
122
+ const { appearance = 'neutral' } = useBannerContext()
123
+ const styles = useStyles({ appearance })
124
+
125
+ const iconNameMap = {
126
+ error: 'general.exclamationTriangle',
127
+ info: 'general.outlinedInfoCircle',
128
+ neutral: 'general.outlinedInfoCircle',
129
+ success: 'general.check',
130
+ warning: 'general.exclamationTriangle',
131
+ } as const
132
+
133
+ return (
134
+ <Icon
135
+ name={iconName || iconNameMap[appearance]}
136
+ style={styles.icon}
137
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
138
+ />
139
+ )
140
+ }
141
+
142
+ BannerStatusIcon.displayName = 'Banner.StatusIcon'
143
+
144
+ // ========================================
145
+ // ====== BannerHeading ===================
146
+ // ========================================
147
+
148
+ interface BannerHeadingProps {
149
+ children: ReactNode
150
+ }
151
+
152
+ function BannerHeading({ children }: BannerHeadingProps) {
153
+ const { appearance = 'neutral' } = useBannerContext()
154
+ const styles = useStyles({ appearance })
155
+
156
+ return (
157
+ <Heading variant="h3" style={styles.heading}>
158
+ {children}
159
+ </Heading>
160
+ )
161
+ }
162
+
163
+ BannerHeading.displayName = 'Banner.Heading'
164
+
165
+ // ========================================
166
+ // ====== BannerText ======================
167
+ // ========================================
168
+
169
+ interface BannerTextProps {
170
+ children: ReactNode
171
+ }
172
+
173
+ function BannerText({ children }: BannerTextProps) {
174
+ const { appearance = 'neutral' } = useBannerContext()
175
+ const styles = useStyles({ appearance })
176
+
177
+ return (
178
+ <Text variant="tertiary" style={styles.text}>
179
+ {children}
180
+ </Text>
181
+ )
182
+ }
183
+
184
+ BannerText.displayName = 'Banner.Text'
185
+
186
+ // ========================================
187
+ // ====== BannerLink ======================
188
+ // ========================================
189
+
190
+ interface BannerLinkProps {
191
+ children: ReactNode
192
+ onPress?: () => void
193
+ }
194
+
195
+ function BannerLink({ children, onPress }: BannerLinkProps) {
196
+ const { appearance = 'neutral' } = useBannerContext()
197
+ const styles = useStyles({ appearance })
198
+
199
+ return (
200
+ <TextInlineButton variant="tertiary" style={styles.text} onPress={onPress}>
201
+ {children}
202
+ </TextInlineButton>
203
+ )
204
+ }
205
+
206
+ BannerLink.displayName = 'Banner.Link'
207
+
208
+ // ========================================
209
+ // ====== Styles ==========================
210
+ // ========================================
211
+
212
+ interface Styles {
213
+ appearance?: StatusAppearanceUnion
214
+ }
215
+
216
+ const useStyles = ({ appearance = 'neutral' }: Styles = {}) => {
217
+ const statusColorMap = useStatusColorAppearanceMap()
218
+ const fontScale = useFontScale()
219
+
220
+ return StyleSheet.create({
221
+ staticLayout: {
222
+ flexDirection: 'row',
223
+ backgroundColor: statusColorMap[appearance].background,
224
+ padding: space(1.5),
225
+ gap: space(1),
226
+ borderRadius: tokens.borderRadiusMd,
227
+ flex: 1,
228
+ },
229
+ content: {
230
+ gap: space(0.5),
231
+ flex: 1,
232
+ },
233
+ icon: {
234
+ color: statusColorMap[appearance].icon,
235
+ fontSize: tokens.fontSizeMd,
236
+ marginTop: space(0.5) * fontScale,
237
+ },
238
+ heading: {
239
+ color: statusColorMap[appearance].text,
240
+ fontWeight: platformFontWeightMedium,
241
+ fontSize: tokens.fontSizeMd,
242
+ },
243
+ text: {
244
+ color: statusColorMap[appearance].text,
245
+ },
246
+ })
247
+ }
@@ -1,11 +1,11 @@
1
1
  import { QueryClient, QueryClientProvider, QueryKey } from '@tanstack/react-query'
2
2
  import React, { useContext, useEffect, useRef } from 'react'
3
3
  import { ViewProps } from 'react-native'
4
- import { Client } from '../utils'
5
4
  import { ChatContext, ChatContextValue } from './chat_context'
6
5
  import { RequestQueryKey } from '../hooks'
6
+ import { ApiClient, useApiClient } from '../hooks/use_api_client'
7
7
 
8
- let apiClient: Client | undefined
8
+ let apiClient: ApiClient | undefined
9
9
 
10
10
  const defaultQueryFn = ({ queryKey }: { queryKey: QueryKey }) => {
11
11
  if (!apiClient) {
@@ -14,7 +14,7 @@ const defaultQueryFn = ({ queryKey }: { queryKey: QueryKey }) => {
14
14
 
15
15
  const [url, data, headers] = queryKey as RequestQueryKey
16
16
 
17
- return apiClient.get({ url, data, headers })
17
+ return apiClient.chat.get({ url, data, headers })
18
18
  }
19
19
 
20
20
  export const queryClient = new QueryClient({
@@ -27,10 +27,10 @@ export const queryClient = new QueryClient({
27
27
  })
28
28
 
29
29
  export function ApiProvider({ children }: ViewProps) {
30
- const { token, env, client } = useContext(ChatContext)
30
+ const { token, env } = useContext(ChatContext)
31
31
  const sessionChanged = useSessionChanged({ token, env })
32
32
 
33
- apiClient = client
33
+ apiClient = useApiClient()
34
34
 
35
35
  useEffect(() => {
36
36
  if (!sessionChanged) return
@@ -2,7 +2,7 @@ import { merge } from 'lodash'
2
2
  import React, { createContext, useMemo } from 'react'
3
3
  import { ColorSchemeName, useColorScheme } from 'react-native'
4
4
  import { DeepPartial, OAuthToken } from '../types'
5
- import { Client, ENV, Session } from '../utils'
5
+ import { ENV, Session } from '../utils'
6
6
  import { ChatTheme, defaultTheme, DefaultTheme } from '../utils/theme'
7
7
 
8
8
  export type ChatContextValue = {
@@ -10,49 +10,32 @@ export type ChatContextValue = {
10
10
  onTokenExpired: () => void
11
11
  theme: ChatTheme
12
12
  env?: ENV
13
- client: Client
13
+ session: Session
14
14
  }
15
15
 
16
16
  export interface ChatProviderProps extends Omit<ChatContextValue, 'client' | 'theme'> {
17
17
  theme: CreateChatThemeProps
18
18
  }
19
19
 
20
- const defaultChatClient = new Client({
21
- app: 'chat',
22
- session: new Session(),
23
- version: '2018-11-01',
24
- onTokenExpired: () => null,
25
- })
26
-
27
20
  export const ChatContext = createContext<ChatContextValue>({
28
21
  theme: defaultTheme('light'),
29
22
  token: undefined,
30
23
  env: undefined,
31
24
  onTokenExpired: () => {},
32
- client: defaultChatClient,
25
+ session: new Session(),
33
26
  })
34
27
 
35
28
  export function ChatProvider({ children, value }: { children: any; value: ChatProviderProps }) {
36
29
  const { env, token, onTokenExpired } = value
37
30
  const theme = useCreateChatTheme(value.theme || {})
38
31
  const session = useMemo(() => new Session({ token, env }), [env, token])
39
- const client = useMemo(
40
- () =>
41
- new Client({
42
- app: 'chat',
43
- session,
44
- version: '2018-11-01',
45
- onTokenExpired,
46
- }),
47
- [onTokenExpired, session]
48
- )
49
32
 
50
33
  const contextValue: ChatContextValue = {
51
34
  env,
52
35
  token,
53
36
  onTokenExpired,
37
+ session,
54
38
  theme,
55
- client,
56
39
  }
57
40
 
58
41
  return <ChatContext.Provider value={contextValue}>{children}</ChatContext.Provider>