@planningcenter/chat-react-native 3.44.5-rc.0 → 3.45.1-qa-897.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 (44) hide show
  1. package/build/components/conversation/message.js +2 -2
  2. package/build/components/conversation/message.js.map +1 -1
  3. package/build/components/conversation/message_form.js +2 -2
  4. package/build/components/conversation/message_form.js.map +1 -1
  5. package/build/components/conversation/message_reaction.js +4 -4
  6. package/build/components/conversation/message_reaction.js.map +1 -1
  7. package/build/components/display/toggle_button.js +9 -5
  8. package/build/components/display/toggle_button.js.map +1 -1
  9. package/build/hooks/index.d.ts +2 -1
  10. package/build/hooks/index.d.ts.map +1 -1
  11. package/build/hooks/index.js +2 -1
  12. package/build/hooks/index.js.map +1 -1
  13. package/build/hooks/use_interaction_tinted_background_color.d.ts +2 -0
  14. package/build/hooks/use_interaction_tinted_background_color.d.ts.map +1 -0
  15. package/build/hooks/use_interaction_tinted_background_color.js +11 -0
  16. package/build/hooks/use_interaction_tinted_background_color.js.map +1 -0
  17. package/build/hooks/use_selected_chip_background_color.d.ts +2 -0
  18. package/build/hooks/use_selected_chip_background_color.d.ts.map +1 -0
  19. package/build/hooks/use_selected_chip_background_color.js +11 -0
  20. package/build/hooks/use_selected_chip_background_color.js.map +1 -0
  21. package/build/screens/design_system_screen.js +3 -3
  22. package/build/screens/design_system_screen.js.map +1 -1
  23. package/build/utils/theme.d.ts +16 -0
  24. package/build/utils/theme.d.ts.map +1 -1
  25. package/build/utils/theme.js +9 -0
  26. package/build/utils/theme.js.map +1 -1
  27. package/package.json +3 -3
  28. package/src/__tests__/hooks/use_selected_chip_background_color.test.tsx +78 -0
  29. package/src/__tests__/utils/theme.ts +23 -0
  30. package/src/components/conversation/message.tsx +2 -2
  31. package/src/components/conversation/message_form.tsx +2 -2
  32. package/src/components/conversation/message_reaction.tsx +4 -4
  33. package/src/components/display/__tests__/toggle_button.test.tsx +135 -0
  34. package/src/components/display/toggle_button.tsx +9 -5
  35. package/src/hooks/index.ts +2 -1
  36. package/src/hooks/use_interaction_tinted_background_color.ts +16 -0
  37. package/src/hooks/use_selected_chip_background_color.ts +16 -0
  38. package/src/screens/design_system_screen.tsx +3 -3
  39. package/src/utils/theme.ts +25 -0
  40. package/build/hooks/use_interaction_ghost_color.d.ts +0 -2
  41. package/build/hooks/use_interaction_ghost_color.d.ts.map +0 -1
  42. package/build/hooks/use_interaction_ghost_color.js +0 -14
  43. package/build/hooks/use_interaction_ghost_color.js.map +0 -1
  44. package/src/hooks/use_interaction_ghost_color.ts +0 -15
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform, PlatformColor } from 'react-native'\nimport type { ColorSchemeName, ColorValue, OpaqueColorValue } from 'react-native'\nimport { aliasTokensColorMap } from '../vendor/tapestry/alias_tokens_color_map'\nimport { tokens } from '../vendor/tapestry/tokens'\n\nexport interface ChatTheme extends DefaultTheme {\n colors: DefaultTheme['colors'] &\n (typeof aliasTokensColorMap.light | typeof aliasTokensColorMap.dark)\n}\n\n/** =============================================\n NOTE: The specific values for `colors` and the `productBadge` are temporary examples that can be replaced once we start building out UI. This line's comment can be removed at that time too.\n\n The default theme is intended to support two types of customizations:\n 1. Specific color properties for a chat component (eg. `primaryButtonBackgroundColor`)\n 2. Any styles for a specific component. (Use only one level of nesting.)\n ```\n primaryButton: {\n borderRadius: number\n container: ViewStyle\n text: TextStyle\n }\n ```\n============================================= */\n\nexport interface DefaultTheme {\n colors: ChatColors\n button: {\n borderRadius: number\n }\n showBadgeProductLogo: boolean\n}\n\nexport const defaultTheme = (colorScheme: ColorSchemeName | null): ChatTheme => {\n const scheme: 'light' | 'dark' = colorScheme === 'dark' ? 'dark' : 'light'\n\n const defaultColors = {\n ...chatThemeColorMap[scheme],\n ...aliasTokensColorMap[scheme],\n }\n\n return {\n colors: defaultColors,\n button: {\n borderRadius: 40,\n },\n showBadgeProductLogo: true, // Overrides visibility of the product logo in `src/display/badge.tsx`\n }\n}\n\nexport type TemporaryDefaultColorsType = Partial<ChatColors>\n\ninterface ChatColors {\n name: string\n buttonStart: string | undefined\n buttonEnd: string | undefined\n interaction: string\n androidModalHeaderButtonTextColor: ColorValue | string | undefined\n iOSModalHeaderButtonTextColor: OpaqueColorValue | string | undefined\n androidSwitchThumbColor: string | undefined\n conversationActionsBackground: string\n testColor: string\n statusSuccessIcon: string\n statusSuccessText: string\n statusSuccessBorder: string\n statusSuccessFill: string\n statusInfoIcon: string\n statusInfoText: string\n statusInfoBorder: string\n statusInfoFill: string\n statusWarningIcon: string\n statusWarningText: string\n statusWarningBorder: string\n statusWarningFill: string\n statusErrorIcon: string\n statusErrorText: string\n statusErrorBorder: string\n statusErrorFill: string\n statusSuccessComposedIcon: string\n statusSuccessComposedText: string\n statusSuccessComposedBackground: string\n statusInfoComposedIcon: string\n statusInfoComposedText: string\n statusInfoComposedBackground: string\n statusWarningComposedIcon: string\n statusWarningComposedText: string\n statusWarningComposedBackground: string\n statusErrorComposedIcon: string\n statusErrorComposedText: string\n statusErrorComposedBackground: string\n statusNeutralComposedIcon: string\n statusNeutralComposedText: string\n statusNeutralComposedBackground: string\n}\n\n// 'link' is an iOS-only semantic color name — constructing it on Android is\n// undefined behavior, so only build it when the code is actually running on iOS\nconst iOSLinkColor = Platform.OS === 'ios' ? PlatformColor('link') : undefined\n\nconst colorsChatLight: ChatColors = {\n name: 'light',\n androidModalHeaderButtonTextColor: tokens.fillColorInteractionDefault,\n iOSModalHeaderButtonTextColor: iOSLinkColor,\n buttonStart: undefined,\n buttonEnd: undefined,\n interaction: tokens.fillColorInteractionDefault,\n androidSwitchThumbColor: undefined,\n conversationActionsBackground: tokens.colorNeutral100White,\n testColor: 'hotpink',\n statusInfoIcon: tokens.iconColorStatusInfoPrimary,\n statusInfoText: tokens.textColorStatusInfo,\n statusInfoBorder: tokens.borderColorStatusInfo,\n statusInfoFill: tokens.fillColorStatusInfoSolid,\n statusSuccessIcon: tokens.iconColorStatusSuccessPrimary,\n statusSuccessText: tokens.textColorStatusSuccess,\n statusSuccessBorder: tokens.borderColorStatusSuccess,\n statusSuccessFill: tokens.fillColorStatusSuccessSolid,\n statusWarningIcon: tokens.iconColorStatusWarningPrimary,\n statusWarningText: tokens.textColorStatusWarning,\n statusWarningBorder: tokens.borderColorStatusWarning,\n statusWarningFill: tokens.fillColorStatusWarningSolid,\n statusErrorIcon: tokens.iconColorStatusErrorPrimary,\n statusErrorText: tokens.textColorStatusError,\n statusErrorBorder: tokens.borderColorStatusError,\n statusErrorFill: tokens.fillColorStatusErrorSolid,\n statusInfoComposedIcon: tokens.iconColorStatusInfoPrimary,\n statusInfoComposedText: tokens.textColorStatusInfo,\n statusInfoComposedBackground: tokens.fillColorStatusInfoGhost,\n statusSuccessComposedIcon: tokens.iconColorStatusSuccessPrimary,\n statusSuccessComposedText: tokens.textColorStatusSuccess,\n statusSuccessComposedBackground: tokens.fillColorStatusSuccessGhost,\n statusWarningComposedIcon: tokens.iconColorStatusWarningPrimary,\n statusWarningComposedText: tokens.textColorStatusWarning,\n statusWarningComposedBackground: tokens.fillColorStatusWarningGhost,\n statusErrorComposedIcon: tokens.iconColorStatusErrorPrimary,\n statusErrorComposedText: tokens.textColorStatusError,\n statusErrorComposedBackground: tokens.fillColorStatusErrorGhost,\n statusNeutralComposedIcon: tokens.iconColorStatusNeutralPrimary,\n statusNeutralComposedText: tokens.textColorStatusNeutral,\n statusNeutralComposedBackground: tokens.fillColorStatusNeutralGhost,\n}\n\nconst colorsChatDark: ChatColors = {\n name: 'dark',\n androidModalHeaderButtonTextColor: tokens.fillColorInteractionDefaultDark,\n iOSModalHeaderButtonTextColor: iOSLinkColor,\n buttonStart: undefined,\n buttonEnd: undefined,\n interaction: tokens.fillColorInteractionDefaultDark,\n androidSwitchThumbColor: undefined,\n conversationActionsBackground: tokens.colorNeutral7,\n testColor: 'pink',\n statusInfoIcon: tokens.iconColorStatusInfoPrimaryDark,\n statusInfoText: tokens.textColorStatusInfoDark,\n statusInfoBorder: tokens.borderColorStatusInfoDark,\n statusInfoFill: tokens.fillColorStatusInfoSolidDark,\n statusSuccessIcon: tokens.iconColorStatusSuccessPrimaryDark,\n statusSuccessText: tokens.textColorStatusSuccessDark,\n statusSuccessBorder: tokens.borderColorStatusSuccessDark,\n statusSuccessFill: tokens.fillColorStatusSuccessSolidDark,\n statusWarningIcon: tokens.iconColorStatusWarningPrimaryDark,\n statusWarningText: tokens.textColorStatusWarningDark,\n statusWarningBorder: tokens.borderColorStatusWarningDark,\n statusWarningFill: tokens.fillColorStatusWarningSolidDark,\n statusErrorIcon: tokens.iconColorStatusErrorPrimaryDark,\n statusErrorText: tokens.textColorStatusErrorDark,\n statusErrorBorder: tokens.borderColorStatusErrorDark,\n statusErrorFill: tokens.fillColorStatusErrorSolidDark,\n\n // Note: CCA inverts composed status colors in dark mode\n statusInfoComposedIcon: tokens.iconColorStatusInfoPrimaryDark,\n statusInfoComposedText: tokens.textColorStatusInfoDark,\n statusInfoComposedBackground: tokens.fillColorStatusInfoGhostDark,\n statusSuccessComposedIcon: tokens.iconColorStatusSuccessPrimaryDark,\n statusSuccessComposedText: tokens.textColorStatusSuccessDark,\n statusSuccessComposedBackground: tokens.fillColorStatusSuccessGhostDark,\n statusWarningComposedIcon: tokens.iconColorStatusWarningPrimaryDark,\n statusWarningComposedText: tokens.textColorStatusWarningDark,\n statusWarningComposedBackground: tokens.fillColorStatusWarningGhostDark,\n statusErrorComposedIcon: tokens.iconColorStatusErrorPrimaryDark,\n statusErrorComposedText: tokens.textColorStatusErrorDark,\n statusErrorComposedBackground: tokens.fillColorStatusErrorGhostDark,\n statusNeutralComposedIcon: tokens.iconColorStatusNeutralPrimaryDark,\n statusNeutralComposedText: tokens.textColorStatusNeutralDark,\n statusNeutralComposedBackground: tokens.fillColorStatusNeutralGhostDark,\n}\n\nconst chatThemeColorMap = {\n light: colorsChatLight,\n dark: colorsChatDark,\n}\n"]}
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform, PlatformColor } from 'react-native'\nimport type { ColorSchemeName, ColorValue, OpaqueColorValue } from 'react-native'\nimport { aliasTokensColorMap } from '../vendor/tapestry/alias_tokens_color_map'\nimport { tokens } from '../vendor/tapestry/tokens'\n\nexport interface ChatTheme extends DefaultTheme {\n colors: DefaultTheme['colors'] &\n (typeof aliasTokensColorMap.light | typeof aliasTokensColorMap.dark)\n}\n\n/** =============================================\n NOTE: The specific values for `colors` and the `productBadge` are temporary examples that can be replaced once we start building out UI. This line's comment can be removed at that time too.\n\n The default theme is intended to support two types of customizations:\n 1. Specific color properties for a chat component (eg. `primaryButtonBackgroundColor`)\n 2. Any styles for a specific component. (Use only one level of nesting.)\n ```\n primaryButton: {\n borderRadius: number\n container: ViewStyle\n text: TextStyle\n }\n ```\n============================================= */\n\nexport interface DefaultTheme {\n colors: ChatColors\n button: {\n borderRadius: number\n }\n chip: {\n hslLightnessChipSelected: number\n }\n showBadgeProductLogo: boolean\n}\n\nexport const defaultTheme = (colorScheme: ColorSchemeName | null): ChatTheme => {\n const scheme: 'light' | 'dark' = colorScheme === 'dark' ? 'dark' : 'light'\n\n const defaultColors = {\n ...chatThemeColorMap[scheme],\n ...aliasTokensColorMap[scheme],\n }\n\n return {\n colors: defaultColors,\n button: {\n borderRadius: 40,\n },\n chip: {\n hslLightnessChipSelected: scheme === 'dark' ? 12 : 92,\n },\n showBadgeProductLogo: true, // Overrides visibility of the product logo in `src/display/badge.tsx`\n }\n}\n\nexport type TemporaryDefaultColorsType = Partial<ChatColors>\n\ninterface ChatColors {\n name: string\n buttonStart: string | undefined\n buttonEnd: string | undefined\n interaction: string\n androidModalHeaderButtonTextColor: ColorValue | string | undefined\n iOSModalHeaderButtonTextColor: OpaqueColorValue | string | undefined\n androidSwitchThumbColor: string | undefined\n conversationActionsBackground: string\n testColor: string\n statusSuccessIcon: string\n statusSuccessText: string\n statusSuccessBorder: string\n statusSuccessFill: string\n statusInfoIcon: string\n statusInfoText: string\n statusInfoBorder: string\n statusInfoFill: string\n statusWarningIcon: string\n statusWarningText: string\n statusWarningBorder: string\n statusWarningFill: string\n statusErrorIcon: string\n statusErrorText: string\n statusErrorBorder: string\n statusErrorFill: string\n statusSuccessComposedIcon: string\n statusSuccessComposedText: string\n statusSuccessComposedBackground: string\n statusInfoComposedIcon: string\n statusInfoComposedText: string\n statusInfoComposedBackground: string\n statusWarningComposedIcon: string\n statusWarningComposedText: string\n statusWarningComposedBackground: string\n statusErrorComposedIcon: string\n statusErrorComposedText: string\n statusErrorComposedBackground: string\n statusNeutralComposedIcon: string\n statusNeutralComposedText: string\n statusNeutralComposedBackground: string\n borderColorChip: string\n fillColorChip: string\n textColorChip: string\n /**\n * Selected-chip colors (border/fill/text). Never assign a static default\n * directly — these stay optional so they always fall back to\n * `colors.interaction` via `??` at the read site. Every current consumer\n * overrides `interaction` at runtime, and a seeded default here could win\n * over that override depending on merge order.\n */\n borderColorChipSelected?: string\n fillColorChipSelected?: string\n textColorChipSelected?: string\n}\n\n// 'link' is an iOS-only semantic color name — constructing it on Android is\n// undefined behavior, so only build it when the code is actually running on iOS\nconst iOSLinkColor = Platform.OS === 'ios' ? PlatformColor('link') : undefined\n\nconst colorsChatLight: ChatColors = {\n name: 'light',\n androidModalHeaderButtonTextColor: tokens.fillColorInteractionDefault,\n iOSModalHeaderButtonTextColor: iOSLinkColor,\n buttonStart: undefined,\n buttonEnd: undefined,\n interaction: tokens.fillColorInteractionDefault,\n androidSwitchThumbColor: undefined,\n conversationActionsBackground: tokens.colorNeutral100White,\n testColor: 'hotpink',\n statusInfoIcon: tokens.iconColorStatusInfoPrimary,\n statusInfoText: tokens.textColorStatusInfo,\n statusInfoBorder: tokens.borderColorStatusInfo,\n statusInfoFill: tokens.fillColorStatusInfoSolid,\n statusSuccessIcon: tokens.iconColorStatusSuccessPrimary,\n statusSuccessText: tokens.textColorStatusSuccess,\n statusSuccessBorder: tokens.borderColorStatusSuccess,\n statusSuccessFill: tokens.fillColorStatusSuccessSolid,\n statusWarningIcon: tokens.iconColorStatusWarningPrimary,\n statusWarningText: tokens.textColorStatusWarning,\n statusWarningBorder: tokens.borderColorStatusWarning,\n statusWarningFill: tokens.fillColorStatusWarningSolid,\n statusErrorIcon: tokens.iconColorStatusErrorPrimary,\n statusErrorText: tokens.textColorStatusError,\n statusErrorBorder: tokens.borderColorStatusError,\n statusErrorFill: tokens.fillColorStatusErrorSolid,\n statusInfoComposedIcon: tokens.iconColorStatusInfoPrimary,\n statusInfoComposedText: tokens.textColorStatusInfo,\n statusInfoComposedBackground: tokens.fillColorStatusInfoGhost,\n statusSuccessComposedIcon: tokens.iconColorStatusSuccessPrimary,\n statusSuccessComposedText: tokens.textColorStatusSuccess,\n statusSuccessComposedBackground: tokens.fillColorStatusSuccessGhost,\n statusWarningComposedIcon: tokens.iconColorStatusWarningPrimary,\n statusWarningComposedText: tokens.textColorStatusWarning,\n statusWarningComposedBackground: tokens.fillColorStatusWarningGhost,\n statusErrorComposedIcon: tokens.iconColorStatusErrorPrimary,\n statusErrorComposedText: tokens.textColorStatusError,\n statusErrorComposedBackground: tokens.fillColorStatusErrorGhost,\n statusNeutralComposedIcon: tokens.iconColorStatusNeutralPrimary,\n statusNeutralComposedText: tokens.textColorStatusNeutral,\n statusNeutralComposedBackground: tokens.fillColorStatusNeutralGhost,\n borderColorChip: tokens.colorNeutral88,\n fillColorChip: 'transparent',\n textColorChip: tokens.colorNeutral45,\n}\n\nconst colorsChatDark: ChatColors = {\n name: 'dark',\n androidModalHeaderButtonTextColor: tokens.fillColorInteractionDefaultDark,\n iOSModalHeaderButtonTextColor: iOSLinkColor,\n buttonStart: undefined,\n buttonEnd: undefined,\n interaction: tokens.fillColorInteractionDefaultDark,\n androidSwitchThumbColor: undefined,\n conversationActionsBackground: tokens.colorNeutral7,\n testColor: 'pink',\n statusInfoIcon: tokens.iconColorStatusInfoPrimaryDark,\n statusInfoText: tokens.textColorStatusInfoDark,\n statusInfoBorder: tokens.borderColorStatusInfoDark,\n statusInfoFill: tokens.fillColorStatusInfoSolidDark,\n statusSuccessIcon: tokens.iconColorStatusSuccessPrimaryDark,\n statusSuccessText: tokens.textColorStatusSuccessDark,\n statusSuccessBorder: tokens.borderColorStatusSuccessDark,\n statusSuccessFill: tokens.fillColorStatusSuccessSolidDark,\n statusWarningIcon: tokens.iconColorStatusWarningPrimaryDark,\n statusWarningText: tokens.textColorStatusWarningDark,\n statusWarningBorder: tokens.borderColorStatusWarningDark,\n statusWarningFill: tokens.fillColorStatusWarningSolidDark,\n statusErrorIcon: tokens.iconColorStatusErrorPrimaryDark,\n statusErrorText: tokens.textColorStatusErrorDark,\n statusErrorBorder: tokens.borderColorStatusErrorDark,\n statusErrorFill: tokens.fillColorStatusErrorSolidDark,\n\n // Note: CCA inverts composed status colors in dark mode\n statusInfoComposedIcon: tokens.iconColorStatusInfoPrimaryDark,\n statusInfoComposedText: tokens.textColorStatusInfoDark,\n statusInfoComposedBackground: tokens.fillColorStatusInfoGhostDark,\n statusSuccessComposedIcon: tokens.iconColorStatusSuccessPrimaryDark,\n statusSuccessComposedText: tokens.textColorStatusSuccessDark,\n statusSuccessComposedBackground: tokens.fillColorStatusSuccessGhostDark,\n statusWarningComposedIcon: tokens.iconColorStatusWarningPrimaryDark,\n statusWarningComposedText: tokens.textColorStatusWarningDark,\n statusWarningComposedBackground: tokens.fillColorStatusWarningGhostDark,\n statusErrorComposedIcon: tokens.iconColorStatusErrorPrimaryDark,\n statusErrorComposedText: tokens.textColorStatusErrorDark,\n statusErrorComposedBackground: tokens.fillColorStatusErrorGhostDark,\n statusNeutralComposedIcon: tokens.iconColorStatusNeutralPrimaryDark,\n statusNeutralComposedText: tokens.textColorStatusNeutralDark,\n statusNeutralComposedBackground: tokens.fillColorStatusNeutralGhostDark,\n borderColorChip: tokens.colorNeutral24,\n fillColorChip: 'transparent',\n textColorChip: tokens.colorNeutral68,\n}\n\nconst chatThemeColorMap = {\n light: colorsChatLight,\n dark: colorsChatDark,\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.44.5-rc.0",
3
+ "version": "3.45.1-qa-897.0",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,7 +31,7 @@
31
31
  "dependencies": {
32
32
  "@fortawesome/fontawesome-svg-core": "^7.2.0",
33
33
  "@fortawesome/react-native-fontawesome": "^0.3.2",
34
- "@planningcenter/emoji-keyboard": "3.44.1",
34
+ "@planningcenter/emoji-keyboard": "3.45.1-qa-897.0",
35
35
  "lodash-inflection": "^1.5.0",
36
36
  "react-compiler-runtime": "^1.0.0"
37
37
  },
@@ -78,5 +78,5 @@
78
78
  "sf-symbols-typescript": "^2.2.0",
79
79
  "typescript": "~6.0.3"
80
80
  },
81
- "gitHead": "5a39c0743737de93c1052fa502479851ea1bf424"
81
+ "gitHead": "a293c586d6b282819a63d71cc443157d59d5ea24"
82
82
  }
@@ -0,0 +1,78 @@
1
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2
+ import { renderHook } from '@testing-library/react-native'
3
+ import React from 'react'
4
+ import { buildTestQueryClient } from '../../__utils__/query_client'
5
+ import { ChatProvider, CreateChatThemeProps } from '../../contexts/chat_context'
6
+ import { useSelectedChipBackgroundColor } from '../../hooks'
7
+
8
+ let themeProps: CreateChatThemeProps
9
+ let queryClient: QueryClient
10
+
11
+ beforeEach(() => {
12
+ queryClient = buildTestQueryClient({
13
+ defaultOptions: {
14
+ queries: {
15
+ refetchInterval: false,
16
+ refetchOnWindowFocus: false,
17
+ refetchOnReconnect: false,
18
+ },
19
+ },
20
+ })
21
+ })
22
+
23
+ afterEach(() => {
24
+ queryClient.clear()
25
+ queryClient.cancelQueries()
26
+ queryClient.removeQueries()
27
+ })
28
+
29
+ const Wrapper = ({ children }: { children: React.ReactNode }) => {
30
+ return (
31
+ <QueryClientProvider client={queryClient}>
32
+ <ChatProvider value={{ onUnauthorizedResponse: () => {}, theme: themeProps }}>
33
+ {children}
34
+ </ChatProvider>
35
+ </QueryClientProvider>
36
+ )
37
+ }
38
+
39
+ describe('useSelectedChipBackgroundColor', () => {
40
+ test('falls back to colors.interaction when fillColorChipSelected is absent', () => {
41
+ themeProps = { theme: { colors: { interaction: 'rgb(0, 255, 0)' } } }
42
+
43
+ const { result } = renderHook(() => useSelectedChipBackgroundColor(), {
44
+ wrapper: Wrapper,
45
+ })
46
+
47
+ expect(result.current).toBe('hsl(120, 100%, 92%)')
48
+ })
49
+
50
+ test('prefers fillColorChipSelected over colors.interaction when supplied', () => {
51
+ themeProps = {
52
+ theme: {
53
+ colors: { interaction: 'rgb(0, 255, 0)', fillColorChipSelected: 'rgb(255, 0, 0)' },
54
+ },
55
+ }
56
+
57
+ const { result } = renderHook(() => useSelectedChipBackgroundColor(), {
58
+ wrapper: Wrapper,
59
+ })
60
+
61
+ expect(result.current).toBe('hsl(0, 100%, 92%)')
62
+ })
63
+
64
+ test('respects a custom hslLightnessChipSelected', () => {
65
+ themeProps = {
66
+ theme: {
67
+ colors: { interaction: 'rgb(0, 255, 0)' },
68
+ chip: { hslLightnessChipSelected: 50 },
69
+ },
70
+ }
71
+
72
+ const { result } = renderHook(() => useSelectedChipBackgroundColor(), {
73
+ wrapper: Wrapper,
74
+ })
75
+
76
+ expect(result.current).toBe('hsl(120, 100%, 50%)')
77
+ })
78
+ })
@@ -20,4 +20,27 @@ describe('defaultTheme', () => {
20
20
  // render an unstyled or misthemed UI.
21
21
  expect(defaultTheme('unspecified').colors).toMatchObject(aliasTokensColorMap.light)
22
22
  })
23
+
24
+ describe('chip tokens', () => {
25
+ test('seeds static defaults for the non-selected chip trio in both schemes', () => {
26
+ const light = defaultTheme('light').colors
27
+ const dark = defaultTheme('dark').colors
28
+
29
+ expect(light.borderColorChip).toBe('hsl(0, 0%, 88%)')
30
+ expect(light.fillColorChip).toBe('transparent')
31
+ expect(light.textColorChip).toBe('hsl(0, 0%, 45%)')
32
+
33
+ expect(dark.borderColorChip).toBe('hsl(0, 0%, 24%)')
34
+ expect(dark.fillColorChip).toBe('transparent')
35
+ expect(dark.textColorChip).toBe('hsl(0, 0%, 68%)')
36
+ })
37
+
38
+ test('never seeds a static default for the selected chip trio', () => {
39
+ const { colors } = defaultTheme('light')
40
+
41
+ expect(colors.borderColorChipSelected).toBeUndefined()
42
+ expect(colors.fillColorChipSelected).toBeUndefined()
43
+ expect(colors.textColorChipSelected).toBeUndefined()
44
+ })
45
+ })
23
46
  })
@@ -13,7 +13,7 @@ import { MessageReaction } from '../../components/conversation/message_reaction'
13
13
  import { Avatar, Icon, Spinner, Text, TextButton, TextInlineButton } from '../../components/display'
14
14
  import {
15
15
  useAnimatedMessageBackgroundColor,
16
- useInteractionGhostBackgroundColor,
16
+ useInteractionTintedBackgroundColor,
17
17
  useTheme,
18
18
  } from '../../hooks'
19
19
  import { useDeletingIds } from '../../hooks'
@@ -342,7 +342,7 @@ export function Message({
342
342
 
343
343
  const useMessageStyles = (mine: boolean, isDeleting: boolean) => {
344
344
  const { colors } = useTheme()
345
- const myMessageBackgroundColor = useInteractionGhostBackgroundColor()
345
+ const myMessageBackgroundColor = useInteractionTintedBackgroundColor()
346
346
  const { width } = useWindowDimensions()
347
347
  const tabletWidth = width >= 744 // Smallest iPad Mini's width
348
348
 
@@ -17,7 +17,7 @@ import { ChatContext } from '../../contexts/chat_context'
17
17
  import {
18
18
  useCreateAndroidRippleColor,
19
19
  useTheme,
20
- useInteractionGhostBackgroundColor,
20
+ useInteractionTintedBackgroundColor,
21
21
  useScalableNumberOfLines,
22
22
  useFontScale,
23
23
  } from '../../hooks'
@@ -784,7 +784,7 @@ const useMessageFormStyles = () => {
784
784
  const navigationTheme = useNavigationTheme()
785
785
  const buttonSize = 38
786
786
 
787
- const giphyBadgeBackgroundColor = useInteractionGhostBackgroundColor()
787
+ const giphyBadgeBackgroundColor = useInteractionTintedBackgroundColor()
788
788
 
789
789
  return StyleSheet.create({
790
790
  container: {
@@ -3,7 +3,7 @@ import colorFunction from 'color'
3
3
  import React, { useMemo } from 'react'
4
4
  import { StyleSheet } from 'react-native'
5
5
  import { Text } from '../../components/display'
6
- import { useInteractionGhostBackgroundColor, useTheme } from '../../hooks'
6
+ import { useSelectedChipBackgroundColor, useTheme } from '../../hooks'
7
7
  import { useCreateAndroidRippleColor } from '../../hooks/use_create_android_ripple_color'
8
8
  import { useMessageReactionToggle } from '../../hooks/use_message_reaction_toggle'
9
9
  import { MessageResource } from '../../types'
@@ -58,12 +58,12 @@ export function MessageReaction({
58
58
  export const useReactionStyles = ({ mine }: { mine: number }) => {
59
59
  const { colors } = useTheme()
60
60
  const activeBorderColor = useMemo(() => {
61
- return colorFunction(colors.interaction)
61
+ return colorFunction(colors.borderColorChipSelected ?? colors.interaction)
62
62
  .hsl()
63
63
  .lightness(colors.name === 'dark' ? 20 : 80)
64
64
  .string()
65
- }, [colors.interaction, colors.name])
66
- const activeBackgroundColor = useInteractionGhostBackgroundColor()
65
+ }, [colors.borderColorChipSelected, colors.interaction, colors.name])
66
+ const activeBackgroundColor = useSelectedChipBackgroundColor()
67
67
 
68
68
  return StyleSheet.create({
69
69
  reaction: {
@@ -0,0 +1,135 @@
1
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2
+ import { render } from '@testing-library/react-native'
3
+ import React from 'react'
4
+ import { buildTestQueryClient } from '../../../__utils__/query_client'
5
+ import { ChatProvider, CreateChatThemeProps } from '../../../contexts/chat_context'
6
+ import { ToggleButton } from '../toggle_button'
7
+
8
+ let themeProps: CreateChatThemeProps
9
+ let queryClient: QueryClient
10
+
11
+ beforeEach(() => {
12
+ queryClient = buildTestQueryClient({
13
+ defaultOptions: {
14
+ queries: {
15
+ refetchInterval: false,
16
+ refetchOnWindowFocus: false,
17
+ refetchOnReconnect: false,
18
+ },
19
+ },
20
+ })
21
+ })
22
+
23
+ afterEach(() => {
24
+ queryClient.clear()
25
+ queryClient.cancelQueries()
26
+ queryClient.removeQueries()
27
+ })
28
+
29
+ const Wrapper = ({ children }: { children: React.ReactNode }) => {
30
+ return (
31
+ <QueryClientProvider client={queryClient}>
32
+ <ChatProvider
33
+ value={{
34
+ token: {
35
+ access_token: '',
36
+ created_at: 0,
37
+ expires_in: 0,
38
+ scope: '',
39
+ refresh_token: '',
40
+ token_type: '',
41
+ },
42
+ onUnauthorizedResponse: () => {},
43
+ theme: themeProps,
44
+ }}
45
+ >
46
+ {children}
47
+ </ChatProvider>
48
+ </QueryClientProvider>
49
+ )
50
+ }
51
+
52
+ const renderToggleButton = (active: boolean) => {
53
+ const view = render(<ToggleButton active={active} accessibilityLabel="Filter" title="Filter" />, {
54
+ wrapper: Wrapper,
55
+ })
56
+
57
+ return {
58
+ button: view.getByLabelText('Filter'),
59
+ text: view.getByText('Filter'),
60
+ }
61
+ }
62
+
63
+ describe('ToggleButton chip colors', () => {
64
+ describe('backward compatibility (Services / sandbox pass only colors.interaction)', () => {
65
+ const distinctiveGreen = 'rgb(0, 255, 0)'
66
+
67
+ beforeEach(() => {
68
+ themeProps = {
69
+ theme: {
70
+ colors: {
71
+ interaction: distinctiveGreen,
72
+ },
73
+ },
74
+ }
75
+ })
76
+
77
+ test('active state derives border, fill, and text color from colors.interaction', () => {
78
+ const { button, text } = renderToggleButton(true)
79
+
80
+ expect(button).toHaveStyle({ borderColor: distinctiveGreen })
81
+ // The active fill is the green interaction color lightened via the
82
+ // chip-background hook (hsl lightness 92 in the light scheme), not
83
+ // the raw interaction color — pins the hook's transform in place.
84
+ expect(button).toHaveStyle({ backgroundColor: 'hsl(120, 100%, 92%)' })
85
+ expect(text).toHaveStyle({ color: distinctiveGreen })
86
+ })
87
+
88
+ test.each([
89
+ ['light', undefined, 'hsl(0, 0%, 88%)', 'hsl(0, 0%, 45%)'],
90
+ ['dark', 'dark' as const, 'hsl(0, 0%, 24%)', 'hsl(0, 0%, 68%)'],
91
+ ])(
92
+ 'inactive state uses the static chip defaults in the %s scheme',
93
+ (_label, colorScheme, borderColor, color) => {
94
+ themeProps = {
95
+ theme: { colors: { interaction: distinctiveGreen } },
96
+ colorScheme,
97
+ }
98
+
99
+ const { button, text } = renderToggleButton(false)
100
+
101
+ expect(button).toHaveStyle({ borderColor })
102
+ expect(text).toHaveStyle({ color })
103
+ }
104
+ )
105
+ })
106
+
107
+ describe('explicit chip token overrides', () => {
108
+ const explicitBorder = 'rgb(1, 2, 3)'
109
+ const explicitFill = 'rgb(4, 5, 6)'
110
+ const explicitText = 'rgb(7, 8, 9)'
111
+
112
+ beforeEach(() => {
113
+ themeProps = {
114
+ theme: {
115
+ colors: {
116
+ interaction: 'rgb(0, 255, 0)',
117
+ borderColorChipSelected: explicitBorder,
118
+ fillColorChipSelected: explicitFill,
119
+ textColorChipSelected: explicitText,
120
+ },
121
+ },
122
+ }
123
+ })
124
+
125
+ test('active state prefers explicit chip tokens over colors.interaction', () => {
126
+ const { button, text } = renderToggleButton(true)
127
+
128
+ expect(button).toHaveStyle({ borderColor: explicitBorder })
129
+ // fillColorChipSelected still passes through the chip-background hook's
130
+ // lightness transform, so the rendered fill isn't the raw override.
131
+ expect(button).toHaveStyle({ backgroundColor: 'hsl(210, 20%, 92%)' })
132
+ expect(text).toHaveStyle({ color: explicitText })
133
+ })
134
+ })
135
+ })
@@ -5,7 +5,7 @@ import {
5
5
  useTheme,
6
6
  useFontScale,
7
7
  useCreateAndroidRippleColor,
8
- useInteractionGhostBackgroundColor,
8
+ useSelectedChipBackgroundColor,
9
9
  } from '../../hooks'
10
10
  import {
11
11
  MAX_FONT_SIZE_MULTIPLIER_LANDMARK,
@@ -164,16 +164,20 @@ const useStyles = ({ active, maxFontSizeMultiplier }: Partial<ToggleButtonProps>
164
164
  const { colors, button } = useTheme()
165
165
  const fontScale = useFontScale({ maxFontSizeMultiplier })
166
166
 
167
- const activeBackgroundColor = useInteractionGhostBackgroundColor()
167
+ const activeBackgroundColor = useSelectedChipBackgroundColor()
168
168
 
169
- const color = active ? colors.interaction : colors.textColorDefaultSecondary
169
+ const borderColor = active
170
+ ? (colors.borderColorChipSelected ?? colors.interaction)
171
+ : colors.borderColorChip
172
+ const fillColor = active ? activeBackgroundColor : colors.fillColorChip
173
+ const color = active ? (colors.textColorChipSelected ?? colors.interaction) : colors.textColorChip
170
174
 
171
175
  return StyleSheet.create({
172
176
  pressable: {
173
177
  borderRadius: button.borderRadius * fontScale,
174
178
  borderWidth: 1,
175
- borderColor: active ? colors.interaction : colors.borderColorDefaultBase,
176
- backgroundColor: active ? activeBackgroundColor : 'transparent',
179
+ borderColor,
180
+ backgroundColor: fillColor,
177
181
  paddingHorizontal: 16 * fontScale,
178
182
  flexDirection: 'row',
179
183
  alignItems: 'center',
@@ -13,7 +13,8 @@ export * from './use_font_scale'
13
13
  export * from './use_has_direct_messages'
14
14
  export * from './use_groups_groups'
15
15
  export * from './use_groups'
16
- export * from './use_interaction_ghost_color'
16
+ export * from './use_selected_chip_background_color'
17
+ export * from './use_interaction_tinted_background_color'
17
18
  export * from './use_message_reaction_toggle'
18
19
  export * from './use_new_conversation_entry'
19
20
  export * from './use_organization'
@@ -0,0 +1,16 @@
1
+ import colorFunction from 'color'
2
+ import { useMemo } from 'react'
3
+ import { useTheme } from './use_theme'
4
+
5
+ export function useInteractionTintedBackgroundColor() {
6
+ const { colors } = useTheme()
7
+
8
+ return useMemo(
9
+ () =>
10
+ colorFunction(colors.interaction)
11
+ .hsl()
12
+ .lightness(colors.name === 'dark' ? 12 : 92)
13
+ .string(),
14
+ [colors.interaction, colors.name]
15
+ )
16
+ }
@@ -0,0 +1,16 @@
1
+ import colorFunction from 'color'
2
+ import { useMemo } from 'react'
3
+ import { useTheme } from './use_theme'
4
+
5
+ export function useSelectedChipBackgroundColor() {
6
+ const { colors, chip } = useTheme()
7
+
8
+ return useMemo(
9
+ () =>
10
+ colorFunction(colors.fillColorChipSelected ?? colors.interaction)
11
+ .hsl()
12
+ .lightness(chip.hslLightnessChipSelected)
13
+ .string(),
14
+ [colors.fillColorChipSelected, colors.interaction, chip.hslLightnessChipSelected]
15
+ )
16
+ }
@@ -29,7 +29,7 @@ import {
29
29
  import { VideoAttachmentPreview } from '../components/display/video_attachment_preview'
30
30
  import BannerPrimitive from '../components/primitive/banner_primitive'
31
31
  import BlankState from '../components/primitive/blank_state_primitive'
32
- import { useInteractionGhostBackgroundColor, useTheme } from '../hooks'
32
+ import { useSelectedChipBackgroundColor, useTheme } from '../hooks'
33
33
  import {
34
34
  MAX_FONT_SIZE_MULTIPLIER,
35
35
  platformPressedOpacityStyle,
@@ -1325,7 +1325,7 @@ function HapticButton({ title, onPress }: { title: string; onPress: () => void }
1325
1325
 
1326
1326
  const useStyles = () => {
1327
1327
  const { colors } = useTheme()
1328
- const interactionGhostBackgroundColor = useInteractionGhostBackgroundColor()
1328
+ const selectedChipBackgroundColor = useSelectedChipBackgroundColor()
1329
1329
 
1330
1330
  return StyleSheet.create({
1331
1331
  hapticButton: {
@@ -1334,7 +1334,7 @@ const useStyles = () => {
1334
1334
  padding: 16,
1335
1335
  alignItems: 'center',
1336
1336
  justifyContent: 'center',
1337
- backgroundColor: interactionGhostBackgroundColor,
1337
+ backgroundColor: selectedChipBackgroundColor,
1338
1338
  borderWidth: 1,
1339
1339
  borderColor: colors.interaction,
1340
1340
  borderRadius: 8,
@@ -28,6 +28,9 @@ export interface DefaultTheme {
28
28
  button: {
29
29
  borderRadius: number
30
30
  }
31
+ chip: {
32
+ hslLightnessChipSelected: number
33
+ }
31
34
  showBadgeProductLogo: boolean
32
35
  }
33
36
 
@@ -44,6 +47,9 @@ export const defaultTheme = (colorScheme: ColorSchemeName | null): ChatTheme =>
44
47
  button: {
45
48
  borderRadius: 40,
46
49
  },
50
+ chip: {
51
+ hslLightnessChipSelected: scheme === 'dark' ? 12 : 92,
52
+ },
47
53
  showBadgeProductLogo: true, // Overrides visibility of the product logo in `src/display/badge.tsx`
48
54
  }
49
55
  }
@@ -91,6 +97,19 @@ interface ChatColors {
91
97
  statusNeutralComposedIcon: string
92
98
  statusNeutralComposedText: string
93
99
  statusNeutralComposedBackground: string
100
+ borderColorChip: string
101
+ fillColorChip: string
102
+ textColorChip: string
103
+ /**
104
+ * Selected-chip colors (border/fill/text). Never assign a static default
105
+ * directly — these stay optional so they always fall back to
106
+ * `colors.interaction` via `??` at the read site. Every current consumer
107
+ * overrides `interaction` at runtime, and a seeded default here could win
108
+ * over that override depending on merge order.
109
+ */
110
+ borderColorChipSelected?: string
111
+ fillColorChipSelected?: string
112
+ textColorChipSelected?: string
94
113
  }
95
114
 
96
115
  // 'link' is an iOS-only semantic color name — constructing it on Android is
@@ -138,6 +157,9 @@ const colorsChatLight: ChatColors = {
138
157
  statusNeutralComposedIcon: tokens.iconColorStatusNeutralPrimary,
139
158
  statusNeutralComposedText: tokens.textColorStatusNeutral,
140
159
  statusNeutralComposedBackground: tokens.fillColorStatusNeutralGhost,
160
+ borderColorChip: tokens.colorNeutral88,
161
+ fillColorChip: 'transparent',
162
+ textColorChip: tokens.colorNeutral45,
141
163
  }
142
164
 
143
165
  const colorsChatDark: ChatColors = {
@@ -183,6 +205,9 @@ const colorsChatDark: ChatColors = {
183
205
  statusNeutralComposedIcon: tokens.iconColorStatusNeutralPrimaryDark,
184
206
  statusNeutralComposedText: tokens.textColorStatusNeutralDark,
185
207
  statusNeutralComposedBackground: tokens.fillColorStatusNeutralGhostDark,
208
+ borderColorChip: tokens.colorNeutral24,
209
+ fillColorChip: 'transparent',
210
+ textColorChip: tokens.colorNeutral68,
186
211
  }
187
212
 
188
213
  const chatThemeColorMap = {
@@ -1,2 +0,0 @@
1
- export declare function useInteractionGhostBackgroundColor(): string;
2
- //# sourceMappingURL=use_interaction_ghost_color.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_interaction_ghost_color.d.ts","sourceRoot":"","sources":["../../src/hooks/use_interaction_ghost_color.ts"],"names":[],"mappings":"AAIA,wBAAgB,kCAAkC,WAUjD"}
@@ -1,14 +0,0 @@
1
- import colorFunction from 'color';
2
- import { useMemo } from 'react';
3
- import { useTheme } from './use_theme';
4
- export function useInteractionGhostBackgroundColor() {
5
- const { colors } = useTheme();
6
- const interactionGhostColor = useMemo(() => {
7
- return colorFunction(colors.interaction)
8
- .hsl()
9
- .lightness(colors.name === 'dark' ? 12 : 92)
10
- .string();
11
- }, [colors.interaction, colors.name]);
12
- return interactionGhostColor;
13
- }
14
- //# sourceMappingURL=use_interaction_ghost_color.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_interaction_ghost_color.js","sourceRoot":"","sources":["../../src/hooks/use_interaction_ghost_color.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,UAAU,kCAAkC;IAChD,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,qBAAqB,GAAG,OAAO,CAAC,GAAG,EAAE;QACzC,OAAO,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC;aACrC,GAAG,EAAE;aACL,SAAS,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC3C,MAAM,EAAE,CAAA;IACb,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IAErC,OAAO,qBAAqB,CAAA;AAC9B,CAAC","sourcesContent":["import colorFunction from 'color'\nimport { useMemo } from 'react'\nimport { useTheme } from './use_theme'\n\nexport function useInteractionGhostBackgroundColor() {\n const { colors } = useTheme()\n const interactionGhostColor = useMemo(() => {\n return colorFunction(colors.interaction)\n .hsl()\n .lightness(colors.name === 'dark' ? 12 : 92)\n .string()\n }, [colors.interaction, colors.name])\n\n return interactionGhostColor\n}\n"]}
@@ -1,15 +0,0 @@
1
- import colorFunction from 'color'
2
- import { useMemo } from 'react'
3
- import { useTheme } from './use_theme'
4
-
5
- export function useInteractionGhostBackgroundColor() {
6
- const { colors } = useTheme()
7
- const interactionGhostColor = useMemo(() => {
8
- return colorFunction(colors.interaction)
9
- .hsl()
10
- .lightness(colors.name === 'dark' ? 12 : 92)
11
- .string()
12
- }, [colors.interaction, colors.name])
13
-
14
- return interactionGhostColor
15
- }