@helpwave/hightide-native 0.0.8 → 0.1.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 (125) hide show
  1. package/README.md +4 -4
  2. package/package.json +8 -19
  3. package/src/components/card/Card.tsx +41 -0
  4. package/src/components/card/index.ts +1 -0
  5. package/src/components/chat/ChatAttachmentMessageBubble.tsx +246 -0
  6. package/src/components/chat/ChatConversationRow.tsx +21 -16
  7. package/src/components/chat/ChatDateDivider.tsx +2 -2
  8. package/src/components/chat/ChatMessageBubble.tsx +62 -52
  9. package/src/components/chat/ChatMessageComposer.tsx +16 -14
  10. package/src/components/chat/ChatQuickReplyChip.tsx +41 -43
  11. package/src/components/chat/ChatSystemLine.tsx +14 -7
  12. package/src/components/chat/ChatThreadHeader.tsx +60 -6
  13. package/src/components/chat/index.ts +1 -2
  14. package/src/components/index.ts +3 -1
  15. package/src/components/layout/Divider.tsx +60 -0
  16. package/src/components/layout/index.ts +1 -0
  17. package/src/components/list/ListActionItem.tsx +99 -0
  18. package/src/components/list/ListItem.tsx +96 -0
  19. package/src/components/list/ListNavigationItem.tsx +102 -0
  20. package/src/components/list/index.ts +3 -0
  21. package/src/components/user-interaction/Button.tsx +80 -31
  22. package/src/components/user-interaction/Checkbox.tsx +72 -32
  23. package/src/components/user-interaction/IconButton.tsx +68 -30
  24. package/src/components/user-interaction/Input.tsx +61 -14
  25. package/src/components/user-interaction/MultiSelect.tsx +142 -75
  26. package/src/components/user-interaction/SearchBar.tsx +222 -0
  27. package/src/components/user-interaction/Select.tsx +129 -58
  28. package/src/components/user-interaction/Switch.tsx +110 -80
  29. package/src/components/user-interaction/ThemedPressable.tsx +136 -0
  30. package/src/components/user-interaction/index.ts +2 -0
  31. package/src/components/visualization-and-display/Avatar.tsx +112 -93
  32. package/src/components/visualization-and-display/Chip.tsx +22 -22
  33. package/src/components/visualization-and-display/ThemedIcon.tsx +72 -0
  34. package/src/components/visualization-and-display/ThemedText.tsx +38 -0
  35. package/src/components/visualization-and-display/index.ts +2 -1
  36. package/src/global-contexts/HightideProvider.tsx +19 -10
  37. package/src/global-contexts/content-theme/ContentThemeContext.ts +22 -0
  38. package/src/global-contexts/content-theme/ContentThemeProvider.tsx +32 -0
  39. package/src/global-contexts/content-theme/index.ts +2 -0
  40. package/src/global-contexts/debug/forward-exports.ts +10 -0
  41. package/src/global-contexts/debug/index.ts +1 -0
  42. package/src/global-contexts/index.ts +2 -0
  43. package/src/global-contexts/theme/ThemeProvider.tsx +7 -1
  44. package/src/icons/HightideIconRegistry.ts +33 -0
  45. package/src/icons/index.ts +2 -0
  46. package/src/icons/types.ts +11 -0
  47. package/src/theme/adapters/container-adapter.ts +323 -0
  48. package/src/theme/adapters/defined.ts +11 -0
  49. package/src/theme/adapters/icon-style-adapter.ts +10 -0
  50. package/src/theme/adapters/index.ts +4 -0
  51. package/src/theme/adapters/text-style-adapter.ts +16 -0
  52. package/src/theme/index.ts +1 -0
  53. package/src/theme/resolvers/avatar.ts +385 -186
  54. package/src/theme/resolvers/button.ts +50 -82
  55. package/src/theme/resolvers/card.ts +27 -0
  56. package/src/theme/resolvers/chat/attachment-message-bubble.ts +163 -0
  57. package/src/theme/resolvers/chat/chat-theme.ts +69 -0
  58. package/src/theme/resolvers/chat/conversation-list.ts +35 -0
  59. package/src/theme/resolvers/chat/conversation-row.ts +64 -0
  60. package/src/theme/resolvers/chat/date-divider.ts +31 -0
  61. package/src/theme/resolvers/chat/index.ts +11 -0
  62. package/src/theme/resolvers/chat/message-bubble.ts +57 -0
  63. package/src/theme/resolvers/chat/message-composer.ts +38 -0
  64. package/src/theme/resolvers/chat/message-list.ts +27 -0
  65. package/src/theme/resolvers/chat/quick-reply-chip.ts +80 -0
  66. package/src/theme/resolvers/chat/system-line.ts +41 -0
  67. package/src/theme/resolvers/chat/thread-header.ts +85 -0
  68. package/src/theme/resolvers/checkbox.ts +87 -74
  69. package/src/theme/resolvers/chip.ts +30 -67
  70. package/src/theme/resolvers/colorScheme.ts +136 -0
  71. package/src/theme/resolvers/divider.ts +34 -0
  72. package/src/theme/resolvers/icon.ts +21 -0
  73. package/src/theme/resolvers/iconButton.ts +45 -61
  74. package/src/theme/resolvers/index.ts +7 -2
  75. package/src/theme/resolvers/input.ts +64 -42
  76. package/src/theme/resolvers/listItem.ts +115 -0
  77. package/src/theme/resolvers/multiSelect.ts +159 -84
  78. package/src/theme/resolvers/searchBar.ts +121 -0
  79. package/src/theme/resolvers/select.ts +141 -66
  80. package/src/theme/resolvers/switch.ts +59 -53
  81. package/src/theme/resolvers/themedPressable.ts +54 -0
  82. package/src/theme/themes/createHightideTheme.ts +214 -51
  83. package/src/theme/themes/hightideThemes.ts +10 -6
  84. package/src/theme/types/color.ts +2 -59
  85. package/src/theme/types/components/avatar.ts +37 -36
  86. package/src/theme/types/components/button.ts +13 -14
  87. package/src/theme/types/components/card.ts +9 -0
  88. package/src/theme/types/components/chat.ts +124 -103
  89. package/src/theme/types/components/checkbox.ts +11 -12
  90. package/src/theme/types/components/chip.ts +8 -14
  91. package/src/theme/types/components/divider.ts +18 -0
  92. package/src/theme/types/components/hightide.ts +41 -42
  93. package/src/theme/types/components/iconButton.ts +19 -14
  94. package/src/theme/types/components/index.ts +5 -1
  95. package/src/theme/types/components/input.ts +17 -8
  96. package/src/theme/types/components/listItem.ts +86 -0
  97. package/src/theme/types/components/multiSelect.ts +14 -12
  98. package/src/theme/types/components/searchBar.ts +28 -0
  99. package/src/theme/types/components/select.ts +21 -9
  100. package/src/theme/types/components/switch.ts +12 -5
  101. package/src/theme/types/components/themedPressable.ts +31 -0
  102. package/src/theme/types/decoration.ts +1 -11
  103. package/src/theme/types/icongraphy.ts +8 -0
  104. package/src/theme/types/index.ts +2 -0
  105. package/src/theme/types/layout.ts +25 -57
  106. package/src/theme/types/resolver.ts +54 -1
  107. package/src/theme/types/semantics.ts +72 -0
  108. package/src/theme/types/theme.ts +26 -13
  109. package/src/theme/types/typography.ts +16 -17
  110. package/src/utils/hitBoxOverlay.ts +44 -0
  111. package/src/utils/index.ts +2 -0
  112. package/src/utils/minimumTouchTargetHitSlop.ts +68 -0
  113. package/src/components/chat/ChatAttachmentCard.tsx +0 -110
  114. package/src/components/chat/ChatMessageCard.tsx +0 -118
  115. package/src/components/menu/Menu.tsx +0 -61
  116. package/src/components/menu/MenuActionItem.tsx +0 -90
  117. package/src/components/menu/MenuItem.tsx +0 -73
  118. package/src/components/menu/MenuNavigationItem.tsx +0 -90
  119. package/src/components/menu/index.ts +0 -4
  120. package/src/components/visualization-and-display/Icon.tsx +0 -27
  121. package/src/storybook/helper.tsx +0 -36
  122. package/src/theme/resolvers/chat.ts +0 -418
  123. package/src/theme/resolvers/coloring.ts +0 -94
  124. package/src/theme/resolvers/menu.ts +0 -120
  125. package/src/theme/types/components/menu.ts +0 -57
@@ -1,36 +0,0 @@
1
- import { Plus } from 'lucide-react-native'
2
-
3
- const iconSelect = {
4
- control: 'select',
5
- options: ['none', 'icon'],
6
- mapping: {
7
- none: undefined,
8
- icon: Plus,
9
- },
10
- } as const
11
-
12
- const exampleSelectValues = [
13
- 'Strawberry',
14
- 'Apple',
15
- 'Banana',
16
- 'Blueberry',
17
- 'Mango',
18
- 'Pineapple',
19
- 'Grapes',
20
- 'Orange',
21
- 'Peach',
22
- 'Watermelon',
23
- 'Kiwi',
24
- 'Cherry',
25
- 'Lemon',
26
- 'Papaya',
27
- 'Raspberry',
28
- 'Blackberry',
29
- ] as const
30
-
31
- export type StorybookHelperSelectType = typeof exampleSelectValues[number]
32
-
33
- export const StorybookHelper = {
34
- iconSelect,
35
- selectValues: exampleSelectValues,
36
- }
@@ -1,418 +0,0 @@
1
- import {
2
- StyleSheet,
3
- type TextStyle,
4
- type ViewStyle
5
- } from 'react-native'
6
-
7
- import { hexWithAlpha } from '@helpwave/hightide-design/utils'
8
- import { fontWeights } from '@helpwave/hightide-design/tokens'
9
- import type {
10
- ComponentColorTokens,
11
- HightideThemeTokens as DesignTokensTheme
12
- } from '@helpwave/hightide-design/types'
13
-
14
- import type {
15
- Color,
16
- HightideSemanticColors
17
- } from '../types/color'
18
- import type {
19
- ChatAttachmentCardState,
20
- ChatConversationRowState,
21
- ChatMessageBubbleState,
22
- ChatMessageCardState,
23
- ChatQuickReplyChipState,
24
- ChatSystemLineState,
25
- ChatTheme
26
- } from '../types/components/chat'
27
- import type { HightideComponentThemes } from '../types/components/hightide'
28
- import {
29
- createStyleResolver,
30
- createValueResolver
31
- } from '../types/resolver'
32
-
33
- export type CreateChatThemeOptions = {
34
- semantic: HightideSemanticColors,
35
- component: ComponentColorTokens,
36
- coloring: HightideComponentThemes['coloring'],
37
- }
38
-
39
- export const createChatTheme = ({
40
- semantic,
41
- component,
42
- coloring,
43
- }: CreateChatThemeOptions): ChatTheme => {
44
- const resolveConversationRow = (state: ChatConversationRowState): ViewStyle => {
45
- const pressed = !!state.isPressed && !state.isDisabled
46
-
47
- return {
48
- flexDirection: 'row',
49
- alignItems: 'center',
50
- gap: 12,
51
- width: '100%',
52
- paddingHorizontal: 14,
53
- paddingVertical: 12,
54
- backgroundColor: state.isSelected
55
- ? semantic.background
56
- : pressed
57
- ? semantic.surfaceHover
58
- : 'transparent',
59
- borderLeftWidth: state.isSelected ? 4 : 0,
60
- borderLeftColor: state.isSelected ? semantic.primary : 'transparent',
61
- borderRadius: 6,
62
- }
63
- }
64
-
65
- return {
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,
92
- alignItems: 'center',
93
- justifyContent: 'center',
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
161
-
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
206
-
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>(() => ({
222
- flexDirection: 'row',
223
- alignItems: 'center',
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]
233
-
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]
246
-
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
282
-
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>(() => ({
322
- flexDirection: 'row',
323
- alignItems: 'center',
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,
352
- borderRadius: 999,
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
- },
409
- }
410
- }
411
-
412
- export const createChatThemeFromDesign = (theme: DesignTokensTheme): ChatTheme => {
413
- return createChatTheme({
414
- semantic: theme.semanticColors,
415
- component: theme.componentColors,
416
- coloring: theme.coloring as HightideComponentThemes['coloring'],
417
- })
418
- }
@@ -1,94 +0,0 @@
1
- import {
2
- hexWithAlpha
3
- } from '@helpwave/hightide-design/utils'
4
- import { componentLayouts } from '@helpwave/hightide-design/tokens'
5
- import type {
6
- ButtonColoringStyle,
7
- ChipColoringStyle,
8
- ColoringStyle
9
- } from '@helpwave/hightide-design/types'
10
-
11
- import type {
12
- Color,
13
- HightideSemanticColors
14
- } from '../types/color'
15
- import type { ColoringDefinition } from '../types/components/hightide'
16
- import type { InteractionState } from '../types/resolver'
17
-
18
- export type ResolvedColoringStyles = {
19
- backgroundColor: Color | 'transparent',
20
- color: Color,
21
- borderColor?: Color,
22
- borderWidth: number,
23
- }
24
-
25
- const usesHover = (state: InteractionState): boolean => {
26
- return !!(state.isHovered || state.isPressed) && !state.isDisabled
27
- }
28
-
29
- export const resolveColoringStyles = (
30
- tokens: ColoringDefinition,
31
- coloringStyle: ColoringStyle,
32
- semantic: HightideSemanticColors,
33
- state: InteractionState = {}
34
- ): ResolvedColoringStyles => {
35
- const outlineWidth = componentLayouts.shared.coloringOutlineWidth
36
- const hovered = usesHover(state)
37
-
38
- if (state.isDisabled) {
39
- return {
40
- backgroundColor: semantic.disabled,
41
- color: semantic.onDisabled,
42
- borderWidth: 0,
43
- }
44
- }
45
-
46
- switch (coloringStyle) {
47
- case 'solid':
48
- return {
49
- backgroundColor: hovered ? tokens.hover : tokens.color,
50
- color: tokens.onColor,
51
- borderWidth: 0,
52
- }
53
- case 'text':
54
- return {
55
- backgroundColor: 'transparent',
56
- color: hovered
57
- ? (tokens.textHover ?? tokens.hover)
58
- : (tokens.text ?? tokens.color),
59
- borderWidth: 0,
60
- }
61
- case 'outline':
62
- return {
63
- backgroundColor: 'transparent',
64
- color: hovered
65
- ? (tokens.outlineHover ?? tokens.hover)
66
- : (tokens.outline ?? tokens.color),
67
- borderColor: hovered
68
- ? (tokens.outlineHover ?? tokens.hover)
69
- : (tokens.outline ?? tokens.color),
70
- borderWidth: outlineWidth,
71
- }
72
- case 'tonal':
73
- return {
74
- backgroundColor: hexWithAlpha(tokens.tonalBackground ?? tokens.color, hovered ? 0.28 : 0.2),
75
- color: tokens.tonalText ?? tokens.color,
76
- borderWidth: 0,
77
- }
78
- case 'tonal-outline':
79
- return {
80
- backgroundColor: hexWithAlpha(tokens.tonalBackground ?? tokens.color, hovered ? 0.28 : 0.2),
81
- color: tokens.tonalText ?? tokens.color,
82
- borderColor: hovered
83
- ? (tokens.outlineHover ?? tokens.hover)
84
- : (tokens.outline ?? tokens.color),
85
- borderWidth: outlineWidth,
86
- }
87
- }
88
- }
89
-
90
- export const isOutlineColoringStyle = (
91
- coloringStyle: ButtonColoringStyle | ChipColoringStyle
92
- ): boolean => {
93
- return coloringStyle === 'outline' || coloringStyle === 'tonal-outline'
94
- }
@@ -1,120 +0,0 @@
1
- import { StyleSheet } from 'react-native'
2
-
3
- import { fontWeights } from '@helpwave/hightide-design/tokens'
4
- import type {
5
- ComponentColorTokens,
6
- HightideThemeTokens as DesignTokensTheme
7
- } from '@helpwave/hightide-design/types'
8
-
9
- import type { HightideSemanticColors } from '../types/color'
10
- import type {
11
- MenuActionItemState,
12
- MenuTheme
13
- } from '../types/components/menu'
14
- import {
15
- createStyleResolver,
16
- createValueResolver
17
- } from '../types/resolver'
18
-
19
- export type CreateMenuThemeOptions = {
20
- semantic: HightideSemanticColors,
21
- component: ComponentColorTokens,
22
- }
23
-
24
- export const createMenuTheme = ({
25
- semantic,
26
- component,
27
- }: CreateMenuThemeOptions): MenuTheme => {
28
- const resolveActionItem = (state: MenuActionItemState) => {
29
- const pressed = !!state.isPressed && !state.isDisabled
30
-
31
- return {
32
- flexDirection: 'row' as const,
33
- alignItems: 'center' as const,
34
- minHeight: 64,
35
- gap: 12,
36
- paddingHorizontal: 16,
37
- paddingVertical: 8,
38
- borderBottomWidth: StyleSheet.hairlineWidth,
39
- borderBottomColor: component.divider,
40
- backgroundColor: pressed ? semantic.surfaceHover : ('transparent' as const),
41
- opacity: state.isDisabled ? 0.6 : 1,
42
- }
43
- }
44
-
45
- const resolveItemContent = () => ({
46
- flex: 1,
47
- gap: 4,
48
- justifyContent: 'center' as const,
49
- })
50
-
51
- const resolveActionLabel = (state: MenuActionItemState) => ({
52
- color: state.isDanger ? semantic.negative : semantic.onSurface,
53
- fontSize: 15,
54
- fontWeight: fontWeights.medium,
55
- })
56
-
57
- const resolveActionIcon = (state: MenuActionItemState) => ({
58
- color: state.isDanger ? semantic.negative : semantic.primary,
59
- })
60
-
61
- return {
62
- section: createStyleResolver(() => ({
63
- marginBottom: 20,
64
- gap: 8,
65
- })),
66
- sectionTitle: createStyleResolver(() => ({
67
- color: semantic.description,
68
- fontSize: 12,
69
- fontWeight: fontWeights.bold,
70
- letterSpacing: 0.4,
71
- textTransform: 'uppercase',
72
- paddingHorizontal: 4,
73
- })),
74
- card: createStyleResolver(() => ({
75
- backgroundColor: semantic.surface,
76
- borderRadius: 12,
77
- borderWidth: 1,
78
- borderColor: component.border,
79
- overflow: 'hidden',
80
- })),
81
- item: createStyleResolver(() => ({
82
- flexDirection: 'row' as const,
83
- alignItems: 'center' as const,
84
- minHeight: 64,
85
- paddingHorizontal: 16,
86
- paddingVertical: 8,
87
- borderBottomWidth: StyleSheet.hairlineWidth,
88
- borderBottomColor: component.divider,
89
- gap: 12,
90
- })),
91
- itemContent: createStyleResolver(resolveItemContent),
92
- itemLabel: createStyleResolver(() => ({
93
- color: semantic.description,
94
- fontSize: 12,
95
- })),
96
- itemValue: createStyleResolver(() => ({
97
- color: semantic.onSurface,
98
- fontSize: 15,
99
- fontWeight: fontWeights.medium,
100
- })),
101
- actionItem: createStyleResolver(resolveActionItem),
102
- actionItemContent: createStyleResolver(resolveItemContent),
103
- actionItemLabel: createStyleResolver(resolveActionLabel),
104
- actionItemIcon: createValueResolver(resolveActionIcon),
105
- navigationItem: createStyleResolver(resolveActionItem),
106
- navigationItemContent: createStyleResolver(resolveItemContent),
107
- navigationItemLabel: createStyleResolver(resolveActionLabel),
108
- navigationItemIcon: createValueResolver(resolveActionIcon),
109
- navigationItemTrailing: createValueResolver(() => ({
110
- color: semantic.description,
111
- })),
112
- }
113
- }
114
-
115
- export const createMenuThemeFromDesign = (theme: DesignTokensTheme): MenuTheme => {
116
- return createMenuTheme({
117
- semantic: theme.semanticColors,
118
- component: theme.componentColors,
119
- })
120
- }