@helpwave/hightide-native 0.0.2 → 0.0.6

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 (71) hide show
  1. package/package.json +4 -3
  2. package/src/components/chat/ChatAttachmentCard.tsx +26 -13
  3. package/src/components/chat/ChatConversationList.tsx +12 -8
  4. package/src/components/chat/ChatConversationRow.tsx +21 -13
  5. package/src/components/chat/ChatDateDivider.tsx +18 -8
  6. package/src/components/chat/ChatMessageBubble.tsx +23 -13
  7. package/src/components/chat/ChatMessageCard.tsx +25 -14
  8. package/src/components/chat/ChatMessageComposer.tsx +14 -9
  9. package/src/components/chat/ChatMessageList.tsx +12 -5
  10. package/src/components/chat/ChatQuickReplyChip.tsx +7 -6
  11. package/src/components/chat/ChatSystemLine.tsx +21 -10
  12. package/src/components/chat/ChatThreadHeader.tsx +19 -9
  13. package/src/components/menu/Menu.tsx +16 -6
  14. package/src/components/menu/MenuActionItem.tsx +10 -5
  15. package/src/components/menu/MenuItem.tsx +16 -6
  16. package/src/components/menu/MenuNavigationItem.tsx +11 -6
  17. package/src/components/user-interaction/Button.tsx +18 -11
  18. package/src/components/user-interaction/Checkbox.tsx +26 -7
  19. package/src/components/user-interaction/IconButton.tsx +23 -9
  20. package/src/components/user-interaction/Input.tsx +22 -5
  21. package/src/components/user-interaction/MultiSelect.tsx +14 -7
  22. package/src/components/user-interaction/Select.tsx +11 -4
  23. package/src/components/visualization-and-display/Chip.tsx +21 -9
  24. package/src/components/visualization-and-display/Icon.tsx +27 -0
  25. package/src/components/visualization-and-display/index.ts +1 -0
  26. package/src/global-contexts/HightideContext.ts +4 -1
  27. package/src/global-contexts/HightideProvider.tsx +21 -9
  28. package/src/global-contexts/hightide-config/HightideConfigUtils.ts +15 -12
  29. package/src/global-contexts/localization/LocalizationProvider.tsx +3 -1
  30. package/src/global-contexts/localization/forward-exports.ts +1 -0
  31. package/src/global-contexts/theme/ThemeContext.ts +11 -6
  32. package/src/global-contexts/theme/ThemeProvider.tsx +34 -37
  33. package/src/hooks/useMultiSelect.ts +1 -0
  34. package/src/hooks/useNativeKeyValueStore.ts +7 -1
  35. package/src/hooks/useSelect.ts +1 -0
  36. package/src/theme/resolvers/button.ts +33 -20
  37. package/src/theme/resolvers/chat.ts +370 -336
  38. package/src/theme/resolvers/checkbox.ts +22 -18
  39. package/src/theme/resolvers/chip.ts +27 -19
  40. package/src/theme/resolvers/coloring.ts +21 -17
  41. package/src/theme/resolvers/iconButton.ts +25 -17
  42. package/src/theme/resolvers/input.ts +25 -18
  43. package/src/theme/resolvers/menu.ts +37 -29
  44. package/src/theme/resolvers/multiSelect.ts +20 -16
  45. package/src/theme/resolvers/select.ts +20 -16
  46. package/src/theme/themes/createTheme.ts +42 -17
  47. package/src/theme/themes/nativeThemes.ts +7 -6
  48. package/src/theme/types/color.ts +60 -0
  49. package/src/theme/types/components/button.ts +30 -0
  50. package/src/theme/types/components/chat.ts +198 -0
  51. package/src/theme/types/{checkbox.ts → components/checkbox.ts} +11 -5
  52. package/src/theme/types/components/chip.ts +30 -0
  53. package/src/theme/types/{components.ts → components/hightide.ts} +22 -1
  54. package/src/theme/types/components/iconButton.ts +30 -0
  55. package/src/theme/types/components/index.ts +10 -0
  56. package/src/theme/types/components/input.ts +19 -0
  57. package/src/theme/types/{menu.ts → components/menu.ts} +21 -14
  58. package/src/theme/types/{multiSelect.ts → components/multiSelect.ts} +13 -9
  59. package/src/theme/types/{select.ts → components/select.ts} +18 -11
  60. package/src/theme/types/decoration.ts +11 -0
  61. package/src/theme/types/index.ts +4 -9
  62. package/src/theme/types/layout.ts +46 -0
  63. package/src/theme/types/theme.ts +14 -10
  64. package/src/theme/types/typography.ts +18 -0
  65. package/src/icons/Icon.tsx +0 -35
  66. package/src/icons/index.ts +0 -1
  67. package/src/theme/types/button.ts +0 -18
  68. package/src/theme/types/chat.ts +0 -141
  69. package/src/theme/types/chip.ts +0 -18
  70. package/src/theme/types/iconButton.ts +0 -20
  71. package/src/theme/types/input.ts +0 -15
@@ -1,12 +1,20 @@
1
- import { StyleSheet } from 'react-native'
2
1
  import {
3
- hexWithAlpha,
4
- remToPx,
5
- type ColoringTokensDefinitions,
6
- type ComponentColors,
7
- type DesignTheme as DesignTokensTheme,
8
- type SemanticColors
9
- } from '@helpwave/hightide-design'
2
+ StyleSheet,
3
+ type TextStyle,
4
+ type ViewStyle
5
+ } from 'react-native'
6
+
7
+ import { hexWithAlpha } from '@helpwave/hightide-design/helpers'
8
+ import { fontWeights } from '@helpwave/hightide-design/tokens'
9
+ import type {
10
+ ComponentColorTokens,
11
+ HightideDesignTokens as DesignTokensTheme
12
+ } from '@helpwave/hightide-design/types'
13
+
14
+ import type {
15
+ Color,
16
+ HightideSemanticColors
17
+ } from '../types/color'
10
18
  import type {
11
19
  ChatAttachmentCardState,
12
20
  ChatConversationRowState,
@@ -15,13 +23,17 @@ import type {
15
23
  ChatQuickReplyChipState,
16
24
  ChatSystemLineState,
17
25
  ChatTheme
18
- } from '../types'
19
- import { createStyleResolver, createValueResolver } from '../types/resolver'
26
+ } from '../types/components/chat'
27
+ import type { HightideComponentThemes } from '../types/components/hightide'
28
+ import {
29
+ createStyleResolver,
30
+ createValueResolver
31
+ } from '../types/resolver'
20
32
 
21
33
  export type CreateChatThemeOptions = {
22
- semantic: SemanticColors,
23
- component: ComponentColors,
24
- coloring: ColoringTokensDefinitions,
34
+ semantic: HightideSemanticColors,
35
+ component: ComponentColorTokens,
36
+ coloring: HightideComponentThemes['coloring'],
25
37
  }
26
38
 
27
39
  export const createChatTheme = ({
@@ -29,356 +41,378 @@ export const createChatTheme = ({
29
41
  component,
30
42
  coloring,
31
43
  }: CreateChatThemeOptions): ChatTheme => {
32
- const resolveConversationRow = (state: ChatConversationRowState) => {
44
+ const resolveConversationRow = (state: ChatConversationRowState): ViewStyle => {
33
45
  const pressed = !!state.isPressed && !state.isDisabled
34
46
 
35
47
  return {
36
- flexDirection: 'row' as const,
37
- alignItems: 'center' as const,
38
- gap: remToPx('0.75rem'),
39
- width: '100%' as const,
40
- paddingHorizontal: remToPx('0.875rem'),
41
- paddingVertical: remToPx('0.75rem'),
48
+ flexDirection: 'row',
49
+ alignItems: 'center',
50
+ gap: 12,
51
+ width: '100%',
52
+ paddingHorizontal: 14,
53
+ paddingVertical: 12,
42
54
  backgroundColor: state.isSelected
43
55
  ? semantic.background
44
56
  : pressed
45
57
  ? semantic.surfaceHover
46
- : ('transparent' as const),
47
- borderLeftWidth: state.isSelected ? remToPx('0.25rem') : 0,
48
- borderLeftColor: state.isSelected ? semantic.primary : ('transparent' as const),
49
- borderRadius: remToPx('0.375rem'),
58
+ : 'transparent',
59
+ borderLeftWidth: state.isSelected ? 4 : 0,
60
+ borderLeftColor: state.isSelected ? semantic.primary : 'transparent',
61
+ borderRadius: 6,
50
62
  }
51
63
  }
52
64
 
53
65
  return {
54
- conversationRow: createStyleResolver(resolveConversationRow),
55
- conversationRowTitle: createStyleResolver((state) => ({
56
- flex: 1,
57
- color: semantic.onSurface,
58
- fontSize: remToPx('1rem'),
59
- fontWeight: state.isUnread ? '700' : '500',
60
- })),
61
- conversationRowTimestamp: createStyleResolver((state) => ({
62
- color: state.isUnread ? semantic.primary : semantic.description,
63
- fontSize: remToPx('0.75rem'),
64
- fontWeight: state.isUnread ? '500' : '400',
65
- flexShrink: 0,
66
- })),
67
- conversationRowPreview: createStyleResolver((state) => ({
68
- flex: 1,
69
- color: state.isUnread ? semantic.onSurface : semantic.description,
70
- fontSize: remToPx('0.875rem'),
71
- fontWeight: '300',
72
- })),
73
- conversationRowUnreadBadge: createStyleResolver(() => ({
74
- minWidth: remToPx('1.25rem'),
75
- height: remToPx('1.25rem'),
76
- paddingHorizontal: remToPx('0.375rem'),
77
- borderRadius: 999,
78
- backgroundColor: semantic.primary,
79
- alignItems: 'center',
80
- justifyContent: 'center',
81
- })),
82
- conversationRowUnreadBadgeText: createStyleResolver(() => ({
83
- color: semantic.onPrimary,
84
- fontSize: remToPx('0.6875rem'),
85
- fontWeight: '700',
86
- })),
87
- conversationRowSentIndicator: createValueResolver(() => ({
88
- color: semantic.primary,
89
- })),
90
- conversationList: createStyleResolver(() => ({
91
- flex: 1,
92
- backgroundColor: semantic.surface,
93
- })),
94
- conversationListHeader: createStyleResolver(() => ({
95
- paddingHorizontal: remToPx('0.875rem'),
96
- paddingVertical: remToPx('0.875rem'),
97
- gap: remToPx('0.75rem'),
98
- })),
99
- conversationListFooter: createStyleResolver(() => ({
100
- paddingHorizontal: remToPx('0.875rem'),
101
- paddingVertical: remToPx('0.5rem'),
102
- })),
103
- threadHeader: createStyleResolver(() => ({
104
- flexDirection: 'row',
105
- alignItems: 'center',
106
- gap: remToPx('0.75rem'),
107
- paddingHorizontal: remToPx('0.875rem'),
108
- paddingVertical: remToPx('0.75rem'),
109
- borderBottomWidth: StyleSheet.hairlineWidth,
110
- borderBottomColor: component.divider,
111
- backgroundColor: semantic.surface,
112
- })),
113
- threadHeaderTitle: createStyleResolver(() => ({
114
- color: semantic.onSurface,
115
- fontSize: remToPx('1rem'),
116
- fontWeight: '700',
117
- })),
118
- threadHeaderSubtitle: createStyleResolver(() => ({
119
- color: semantic.description,
120
- fontSize: remToPx('0.75rem'),
121
- fontWeight: '300',
122
- })),
123
- messageList: createStyleResolver(() => ({
124
- flex: 1,
125
- paddingHorizontal: remToPx('1rem'),
126
- paddingVertical: remToPx('1.125rem'),
127
- gap: remToPx('0.75rem'),
128
- backgroundColor: semantic.background,
129
- })),
130
- messageBubbleContainer: createStyleResolver((state: ChatMessageBubbleState) => ({
131
- maxWidth: remToPx('17.5rem'),
132
- gap: remToPx('0.25rem'),
133
- alignSelf: state.direction === 'outgoing' ? 'flex-end' : 'flex-start',
134
- alignItems: state.direction === 'outgoing' ? 'flex-end' : 'flex-start',
135
- })),
136
- messageBubble: createStyleResolver((state: ChatMessageBubbleState) => {
137
- const outgoing = state.direction === 'outgoing'
138
- const radius = remToPx('0.75rem')
139
- const corner = remToPx('0.25rem')
140
-
141
- return {
142
- paddingHorizontal: remToPx('0.9375rem'),
143
- paddingVertical: remToPx('0.6875rem'),
144
- backgroundColor: outgoing ? semantic.primary : semantic.neutral,
145
- borderTopLeftRadius: radius,
146
- borderTopRightRadius: radius,
147
- borderBottomLeftRadius: outgoing ? radius : corner,
148
- borderBottomRightRadius: outgoing ? corner : radius,
149
- }
150
- }),
151
- messageBubbleContent: createStyleResolver((state: ChatMessageBubbleState) => ({
152
- color: state.direction === 'outgoing' ? semantic.onPrimary : semantic.onNeutral,
153
- fontSize: remToPx('1rem'),
154
- fontWeight: '300',
155
- lineHeight: remToPx('1.4rem'),
156
- })),
157
- messageBubbleTimestamp: createStyleResolver((state: ChatMessageBubbleState) => ({
158
- marginTop: remToPx('0.3125rem'),
159
- color: state.direction === 'outgoing'
160
- ? hexWithAlpha(semantic.onPrimary, 0.75)
161
- : semantic.description,
162
- fontSize: remToPx('0.6875rem'),
163
- fontWeight: '500',
164
- textAlign: 'right',
165
- })),
166
- messageBubbleReceipt: createStyleResolver(() => ({
167
- flexDirection: 'row',
168
- alignItems: 'center',
169
- gap: remToPx('0.3125rem'),
170
- })),
171
- messageBubbleReceiptText: createStyleResolver(() => ({
172
- color: semantic.description,
173
- fontSize: remToPx('0.6875rem'),
174
- fontWeight: '500',
175
- })),
176
- messageBubbleReceiptIcon: createValueResolver(() => ({
177
- color: semantic.primary,
178
- })),
179
- messageCard: createStyleResolver((state: ChatMessageCardState) => {
180
- const outgoing = state.direction === 'outgoing'
181
- const radius = remToPx('0.75rem')
182
- const corner = remToPx('0.25rem')
183
-
184
- return {
185
- width: remToPx('18.125rem'),
186
- maxWidth: remToPx('18.75rem'),
187
- backgroundColor: semantic.surface,
188
- borderWidth: 1,
189
- borderColor: component.divider,
190
- borderTopLeftRadius: radius,
191
- borderTopRightRadius: radius,
192
- borderBottomLeftRadius: outgoing ? radius : corner,
193
- borderBottomRightRadius: outgoing ? corner : radius,
194
- overflow: 'hidden',
195
- alignSelf: outgoing ? 'flex-end' : 'flex-start',
196
- }
197
- }),
198
- messageCardHeader: createStyleResolver(() => ({
199
- flexDirection: 'row',
200
- alignItems: 'center',
201
- gap: remToPx('0.625rem'),
202
- paddingHorizontal: remToPx('0.9375rem'),
203
- paddingVertical: remToPx('0.75rem'),
204
- borderBottomWidth: StyleSheet.hairlineWidth,
205
- borderBottomColor: component.divider,
206
- })),
207
- messageCardIcon: createStyleResolver((state: ChatMessageCardState) => {
208
- const color = state.color ?? 'primary'
209
- const tokens = coloring[color]
210
-
211
- return {
212
- width: remToPx('2.25rem'),
213
- height: remToPx('2.25rem'),
214
- borderRadius: remToPx('0.375rem'),
66
+ conversationRow: {
67
+ container: createStyleResolver<ChatConversationRowState, ViewStyle>(resolveConversationRow),
68
+ title: createStyleResolver<ChatConversationRowState, TextStyle>((state) => ({
69
+ flex: 1,
70
+ color: semantic.onSurface,
71
+ fontSize: 16,
72
+ fontWeight: state.isUnread ? fontWeights.bold : fontWeights.medium,
73
+ })),
74
+ timestamp: createStyleResolver<ChatConversationRowState, TextStyle>((state) => ({
75
+ color: state.isUnread ? semantic.primary : semantic.description,
76
+ fontSize: 12,
77
+ fontWeight: state.isUnread ? fontWeights.medium : fontWeights.base,
78
+ flexShrink: 0,
79
+ })),
80
+ preview: createStyleResolver<ChatConversationRowState, TextStyle>((state) => ({
81
+ flex: 1,
82
+ color: state.isUnread ? semantic.onSurface : semantic.description,
83
+ fontSize: 14,
84
+ fontWeight: fontWeights.light,
85
+ })),
86
+ unreadBadge: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
87
+ minWidth: 20,
88
+ height: 20,
89
+ paddingHorizontal: 6,
90
+ borderRadius: 999,
91
+ backgroundColor: semantic.primary,
215
92
  alignItems: 'center',
216
93
  justifyContent: 'center',
217
- backgroundColor: hexWithAlpha(tokens.tonalBackground ?? tokens.color, 0.2),
218
- }
219
- }),
220
- messageCardIconColor: createValueResolver((state: ChatMessageCardState) => {
221
- const color = state.color ?? 'primary'
222
- const tokens = coloring[color]
223
-
224
- return {
225
- color: tokens.tonalText ?? tokens.color,
226
- }
227
- }),
228
- messageCardTitle: createStyleResolver((state: ChatMessageCardState) => {
229
- const color = state.color ?? 'primary'
230
- const tokens = coloring[color]
94
+ })),
95
+ unreadBadgeText: createStyleResolver<Record<string, never>, TextStyle>(() => ({
96
+ color: semantic.onPrimary,
97
+ fontSize: 11,
98
+ fontWeight: fontWeights.bold,
99
+ })),
100
+ sentIndicator: createValueResolver<Record<string, never>, { color: Color }>(() => ({
101
+ color: semantic.primary,
102
+ })),
103
+ },
104
+ conversationList: {
105
+ container: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
106
+ flex: 1,
107
+ backgroundColor: semantic.surface,
108
+ })),
109
+ header: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
110
+ paddingHorizontal: 14,
111
+ paddingVertical: 14,
112
+ gap: 12,
113
+ })),
114
+ footer: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
115
+ paddingHorizontal: 14,
116
+ paddingVertical: 8,
117
+ })),
118
+ },
119
+ threadHeader: {
120
+ container: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
121
+ flexDirection: 'row',
122
+ alignItems: 'center',
123
+ gap: 12,
124
+ paddingHorizontal: 14,
125
+ paddingVertical: 12,
126
+ borderBottomWidth: StyleSheet.hairlineWidth,
127
+ borderBottomColor: component.divider,
128
+ backgroundColor: semantic.surface,
129
+ })),
130
+ title: createStyleResolver<Record<string, never>, TextStyle>(() => ({
131
+ color: semantic.onSurface,
132
+ fontSize: 16,
133
+ fontWeight: fontWeights.bold,
134
+ })),
135
+ subtitle: createStyleResolver<Record<string, never>, TextStyle>(() => ({
136
+ color: semantic.description,
137
+ fontSize: 12,
138
+ fontWeight: fontWeights.light,
139
+ })),
140
+ },
141
+ messageList: {
142
+ container: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
143
+ flex: 1,
144
+ paddingHorizontal: 16,
145
+ paddingVertical: 18,
146
+ gap: 12,
147
+ backgroundColor: semantic.background,
148
+ })),
149
+ },
150
+ messageBubble: {
151
+ container: createStyleResolver<ChatMessageBubbleState, ViewStyle>((state) => ({
152
+ maxWidth: 280,
153
+ gap: 4,
154
+ alignSelf: state.direction === 'outgoing' ? 'flex-end' : 'flex-start',
155
+ alignItems: state.direction === 'outgoing' ? 'flex-end' : 'flex-start',
156
+ })),
157
+ bubble: createStyleResolver<ChatMessageBubbleState, ViewStyle>((state) => {
158
+ const outgoing = state.direction === 'outgoing'
159
+ const radius = 12
160
+ const corner = 4
231
161
 
232
- return {
233
- color: tokens.text ?? tokens.color,
234
- fontSize: remToPx('0.875rem'),
235
- fontWeight: '700',
236
- }
237
- }),
238
- messageCardSubtitle: createStyleResolver(() => ({
239
- color: semantic.description,
240
- fontSize: remToPx('0.75rem'),
241
- })),
242
- messageCardBody: createStyleResolver(() => ({
243
- paddingHorizontal: remToPx('0.9375rem'),
244
- paddingVertical: remToPx('0.75rem'),
245
- gap: remToPx('0.25rem'),
246
- })),
247
- messageCardActions: createStyleResolver(() => ({
248
- flexDirection: 'row',
249
- gap: remToPx('0.625rem'),
250
- paddingHorizontal: remToPx('0.9375rem'),
251
- paddingBottom: remToPx('0.9375rem'),
252
- })),
253
- attachmentCard: createStyleResolver((state: ChatAttachmentCardState) => {
254
- const outgoing = state.direction === 'outgoing'
255
- const radius = remToPx('0.75rem')
256
- const corner = remToPx('0.25rem')
162
+ return {
163
+ paddingHorizontal: 15,
164
+ paddingVertical: 11,
165
+ backgroundColor: outgoing ? semantic.primary : semantic.neutral,
166
+ borderTopLeftRadius: radius,
167
+ borderTopRightRadius: radius,
168
+ borderBottomLeftRadius: outgoing ? radius : corner,
169
+ borderBottomRightRadius: outgoing ? corner : radius,
170
+ }
171
+ }),
172
+ content: createStyleResolver<ChatMessageBubbleState, TextStyle>((state) => ({
173
+ color: state.direction === 'outgoing' ? semantic.onPrimary : semantic.onNeutral,
174
+ fontSize: 16,
175
+ fontWeight: fontWeights.light,
176
+ lineHeight: 22.4,
177
+ })),
178
+ timestamp: createStyleResolver<ChatMessageBubbleState, TextStyle>((state) => ({
179
+ marginTop: 5,
180
+ color: state.direction === 'outgoing'
181
+ ? hexWithAlpha(semantic.onPrimary, 0.75)
182
+ : semantic.description,
183
+ fontSize: 11,
184
+ fontWeight: fontWeights.medium,
185
+ textAlign: 'right',
186
+ })),
187
+ receipt: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
188
+ flexDirection: 'row',
189
+ alignItems: 'center',
190
+ gap: 5,
191
+ })),
192
+ receiptText: createStyleResolver<Record<string, never>, TextStyle>(() => ({
193
+ color: semantic.description,
194
+ fontSize: 11,
195
+ fontWeight: fontWeights.medium,
196
+ })),
197
+ receiptIcon: createValueResolver<Record<string, never>, { color: Color }>(() => ({
198
+ color: semantic.primary,
199
+ })),
200
+ },
201
+ messageCard: {
202
+ container: createStyleResolver<ChatMessageCardState, ViewStyle>((state) => {
203
+ const outgoing = state.direction === 'outgoing'
204
+ const radius = 12
205
+ const corner = 4
257
206
 
258
- return {
207
+ return {
208
+ width: 290,
209
+ maxWidth: 300,
210
+ backgroundColor: semantic.surface,
211
+ borderWidth: 1,
212
+ borderColor: component.divider,
213
+ borderTopLeftRadius: radius,
214
+ borderTopRightRadius: radius,
215
+ borderBottomLeftRadius: outgoing ? radius : corner,
216
+ borderBottomRightRadius: outgoing ? corner : radius,
217
+ overflow: 'hidden',
218
+ alignSelf: outgoing ? 'flex-end' : 'flex-start',
219
+ }
220
+ }),
221
+ header: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
259
222
  flexDirection: 'row',
260
223
  alignItems: 'center',
261
- gap: remToPx('0.75rem'),
262
- maxWidth: remToPx('17.5rem'),
263
- padding: remToPx('0.75rem'),
264
- backgroundColor: semantic.surface,
265
- borderWidth: 1,
266
- borderColor: component.divider,
267
- borderTopLeftRadius: radius,
268
- borderTopRightRadius: radius,
269
- borderBottomLeftRadius: outgoing ? radius : corner,
270
- borderBottomRightRadius: outgoing ? corner : radius,
271
- alignSelf: outgoing ? 'flex-end' : 'flex-start',
272
- }
273
- }),
274
- attachmentCardIcon: createStyleResolver(() => ({
275
- width: remToPx('2.75rem'),
276
- height: remToPx('2.75rem'),
277
- borderRadius: remToPx('0.375rem'),
278
- alignItems: 'center',
279
- justifyContent: 'center',
280
- backgroundColor: hexWithAlpha(semantic.negative, 0.2),
281
- })),
282
- attachmentCardIconColor: createValueResolver(() => ({
283
- color: semantic.negative,
284
- })),
285
- attachmentCardName: createStyleResolver(() => ({
286
- color: semantic.onSurface,
287
- fontSize: remToPx('0.875rem'),
288
- fontWeight: '500',
289
- })),
290
- attachmentCardMetadata: createStyleResolver(() => ({
291
- color: semantic.description,
292
- fontSize: remToPx('0.75rem'),
293
- })),
294
- systemLine: createStyleResolver(() => ({
295
- flexDirection: 'row',
296
- alignItems: 'center',
297
- justifyContent: 'center',
298
- alignSelf: 'center',
299
- gap: remToPx('0.375rem'),
300
- })),
301
- systemLineText: createStyleResolver((state: ChatSystemLineState) => {
302
- const color = state.color ?? 'primary'
303
- const tokens = coloring[color]
224
+ gap: 10,
225
+ paddingHorizontal: 15,
226
+ paddingVertical: 12,
227
+ borderBottomWidth: StyleSheet.hairlineWidth,
228
+ borderBottomColor: component.divider,
229
+ })),
230
+ icon: createStyleResolver<ChatMessageCardState, ViewStyle>((state) => {
231
+ const color = state.color ?? 'primary'
232
+ const tokens = coloring[color]
304
233
 
305
- return {
306
- color: tokens.text ?? tokens.color,
307
- fontSize: remToPx('0.75rem'),
308
- fontWeight: '500',
309
- }
310
- }),
311
- systemLineIcon: createValueResolver((state: ChatSystemLineState) => {
312
- const color = state.color ?? 'primary'
313
- const tokens = coloring[color]
234
+ return {
235
+ width: 36,
236
+ height: 36,
237
+ borderRadius: 6,
238
+ alignItems: 'center',
239
+ justifyContent: 'center',
240
+ backgroundColor: hexWithAlpha(tokens.tonalBackground ?? tokens.color, 0.2),
241
+ }
242
+ }),
243
+ iconColor: createValueResolver<ChatMessageCardState, { color: Color }>((state) => {
244
+ const color = state.color ?? 'primary'
245
+ const tokens = coloring[color]
314
246
 
315
- return {
316
- color: tokens.text ?? tokens.color,
317
- }
318
- }),
319
- dateDivider: createStyleResolver(() => ({
320
- alignSelf: 'center',
321
- paddingHorizontal: remToPx('0.875rem'),
322
- paddingVertical: remToPx('0.25rem'),
323
- borderRadius: 999,
324
- backgroundColor: semantic.surface,
325
- })),
326
- dateDividerText: createStyleResolver(() => ({
327
- color: semantic.description,
328
- fontSize: remToPx('0.75rem'),
329
- fontWeight: '500',
330
- })),
331
- quickReplyChip: createStyleResolver((state: ChatQuickReplyChipState) => {
332
- const pressed = !!state.isPressed && !state.isDisabled
247
+ return {
248
+ color: tokens.tonalText ?? tokens.color,
249
+ }
250
+ }),
251
+ title: createStyleResolver<ChatMessageCardState, TextStyle>((state) => {
252
+ const color = state.color ?? 'primary'
253
+ const tokens = coloring[color]
254
+
255
+ return {
256
+ color: tokens.text ?? tokens.color,
257
+ fontSize: 14,
258
+ fontWeight: fontWeights.bold,
259
+ }
260
+ }),
261
+ subtitle: createStyleResolver<Record<string, never>, TextStyle>(() => ({
262
+ color: semantic.description,
263
+ fontSize: 12,
264
+ })),
265
+ body: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
266
+ paddingHorizontal: 15,
267
+ paddingVertical: 12,
268
+ gap: 4,
269
+ })),
270
+ actions: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
271
+ flexDirection: 'row',
272
+ gap: 10,
273
+ paddingHorizontal: 15,
274
+ paddingBottom: 15,
275
+ })),
276
+ },
277
+ attachmentCard: {
278
+ container: createStyleResolver<ChatAttachmentCardState, ViewStyle>((state) => {
279
+ const outgoing = state.direction === 'outgoing'
280
+ const radius = 12
281
+ const corner = 4
333
282
 
334
- return {
283
+ return {
284
+ flexDirection: 'row',
285
+ alignItems: 'center',
286
+ gap: 12,
287
+ maxWidth: 280,
288
+ padding: 12,
289
+ backgroundColor: semantic.surface,
290
+ borderWidth: 1,
291
+ borderColor: component.divider,
292
+ borderTopLeftRadius: radius,
293
+ borderTopRightRadius: radius,
294
+ borderBottomLeftRadius: outgoing ? radius : corner,
295
+ borderBottomRightRadius: outgoing ? corner : radius,
296
+ alignSelf: outgoing ? 'flex-end' : 'flex-start',
297
+ }
298
+ }),
299
+ icon: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
300
+ width: 44,
301
+ height: 44,
302
+ borderRadius: 6,
303
+ alignItems: 'center',
304
+ justifyContent: 'center',
305
+ backgroundColor: hexWithAlpha(semantic.negative, 0.2),
306
+ })),
307
+ iconColor: createValueResolver<Record<string, never>, { color: Color }>(() => ({
308
+ color: semantic.negative,
309
+ })),
310
+ name: createStyleResolver<Record<string, never>, TextStyle>(() => ({
311
+ color: semantic.onSurface,
312
+ fontSize: 14,
313
+ fontWeight: fontWeights.medium,
314
+ })),
315
+ metadata: createStyleResolver<Record<string, never>, TextStyle>(() => ({
316
+ color: semantic.description,
317
+ fontSize: 12,
318
+ })),
319
+ },
320
+ systemLine: {
321
+ container: createStyleResolver<ChatSystemLineState, ViewStyle>(() => ({
335
322
  flexDirection: 'row',
336
323
  alignItems: 'center',
337
- alignSelf: 'flex-start',
338
- gap: remToPx('0.375rem'),
339
- paddingHorizontal: remToPx('0.875rem'),
340
- paddingVertical: remToPx('0.375rem'),
324
+ justifyContent: 'center',
325
+ alignSelf: 'center',
326
+ gap: 6,
327
+ })),
328
+ text: createStyleResolver<ChatSystemLineState, TextStyle>((state) => {
329
+ const color = state.color ?? 'primary'
330
+ const tokens = coloring[color]
331
+
332
+ return {
333
+ color: tokens.text ?? tokens.color,
334
+ fontSize: 12,
335
+ fontWeight: fontWeights.medium,
336
+ }
337
+ }),
338
+ icon: createValueResolver<ChatSystemLineState, { color: Color }>((state) => {
339
+ const color = state.color ?? 'primary'
340
+ const tokens = coloring[color]
341
+
342
+ return {
343
+ color: tokens.text ?? tokens.color,
344
+ }
345
+ }),
346
+ },
347
+ dateDivider: {
348
+ container: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
349
+ alignSelf: 'center',
350
+ paddingHorizontal: 14,
351
+ paddingVertical: 4,
341
352
  borderRadius: 999,
342
- borderWidth: 1,
343
- borderColor: state.isActive ? semantic.primary : component.divider,
344
- backgroundColor: pressed ? semantic.surfaceHover : semantic.surface,
345
- }
346
- }),
347
- quickReplyChipText: createStyleResolver((state: ChatQuickReplyChipState) => ({
348
- color: state.isActive ? semantic.primary : semantic.description,
349
- fontSize: remToPx('0.875rem'),
350
- fontWeight: '500',
351
- })),
352
- messageComposer: createStyleResolver(() => ({
353
- flexDirection: 'row',
354
- alignItems: 'flex-end',
355
- width: '100%',
356
- gap: remToPx('0.5rem'),
357
- paddingHorizontal: remToPx('0.875rem'),
358
- paddingVertical: remToPx('0.75rem'),
359
- backgroundColor: semantic.surface,
360
- borderTopWidth: StyleSheet.hairlineWidth,
361
- borderTopColor: component.divider,
362
- })),
363
- messageComposerInput: createStyleResolver(() => ({
364
- flex: 1,
365
- minHeight: remToPx('2.75rem'),
366
- maxHeight: remToPx('2.75rem') * 7,
367
- paddingHorizontal: remToPx('0.75rem'),
368
- paddingVertical: remToPx('0.75rem'),
369
- borderRadius: remToPx('0.375rem'),
370
- backgroundColor: semantic.surfaceVariant,
371
- color: semantic.onSurface,
372
- fontSize: remToPx('0.9375rem'),
373
- })),
374
- messageComposerPlaceholderColor: createValueResolver(() => semantic.placeholder),
353
+ backgroundColor: semantic.surface,
354
+ })),
355
+ text: createStyleResolver<Record<string, never>, TextStyle>(() => ({
356
+ color: semantic.description,
357
+ fontSize: 12,
358
+ fontWeight: fontWeights.medium,
359
+ })),
360
+ },
361
+ quickReplyChip: {
362
+ container: createStyleResolver<ChatQuickReplyChipState, ViewStyle>((state) => {
363
+ const pressed = !!state.isPressed && !state.isDisabled
364
+
365
+ return {
366
+ flexDirection: 'row',
367
+ alignItems: 'center',
368
+ alignSelf: 'flex-start',
369
+ gap: 6,
370
+ paddingHorizontal: 14,
371
+ paddingVertical: 6,
372
+ borderRadius: 999,
373
+ borderWidth: 1,
374
+ borderColor: state.isActive ? semantic.primary : component.divider,
375
+ backgroundColor: pressed ? semantic.surfaceHover : semantic.surface,
376
+ }
377
+ }),
378
+ text: createStyleResolver<ChatQuickReplyChipState, TextStyle>((state) => ({
379
+ color: state.isActive ? semantic.primary : semantic.description,
380
+ fontSize: 14,
381
+ fontWeight: fontWeights.medium,
382
+ })),
383
+ },
384
+ messageComposer: {
385
+ container: createStyleResolver<Record<string, never>, ViewStyle>(() => ({
386
+ flexDirection: 'row',
387
+ alignItems: 'flex-end',
388
+ width: '100%',
389
+ gap: 8,
390
+ paddingHorizontal: 14,
391
+ paddingVertical: 12,
392
+ backgroundColor: semantic.surface,
393
+ borderTopWidth: StyleSheet.hairlineWidth,
394
+ borderTopColor: component.divider,
395
+ })),
396
+ input: createStyleResolver<Record<string, never>, TextStyle>(() => ({
397
+ flex: 1,
398
+ minHeight: 44,
399
+ maxHeight: 44 * 7,
400
+ paddingHorizontal: 12,
401
+ paddingVertical: 12,
402
+ borderRadius: 6,
403
+ backgroundColor: semantic.surfaceVariant,
404
+ color: semantic.onSurface,
405
+ fontSize: 15,
406
+ })),
407
+ placeholderColor: createValueResolver<Record<string, never>, Color>(() => semantic.placeholder),
408
+ },
375
409
  }
376
410
  }
377
411
 
378
412
  export const createChatThemeFromDesign = (theme: DesignTokensTheme): ChatTheme => {
379
413
  return createChatTheme({
380
- semantic: theme.semantic,
381
- component: theme.component,
382
- coloring: theme.coloring,
414
+ semantic: theme.semanticColors,
415
+ component: theme.componentColors,
416
+ coloring: theme.coloring as HightideComponentThemes['coloring'],
383
417
  })
384
418
  }