@helpwave/hightide-native 0.3.1 → 0.4.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.
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "access": "public"
11
11
  },
12
12
  "license": "AGPL-3.0-only",
13
- "version": "0.3.1",
13
+ "version": "0.4.0",
14
14
  "type": "module",
15
15
  "files": [
16
16
  "src"
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "lucide-react-native": "0.561.0",
46
- "@helpwave/hightide-design": "0.3.0",
47
- "@helpwave/hightide-utils": "0.1.0"
46
+ "@helpwave/hightide-utils": "0.1.0",
47
+ "@helpwave/hightide-design": "0.4.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@react-native-async-storage/async-storage": ">=2.0.0",
@@ -57,7 +57,7 @@ const mergeBubbleStyleOverwrite = <TStyle extends StyleProp<ViewStyle> | object>
57
57
  tokenOverride: TStyle,
58
58
  userOverwrite?: StyleOverwrite<ChatMessageBubbleState, TStyle>
59
59
  ): StyleOverwrite<ChatMessageBubbleState, TStyle> => (
60
- (prev, state) => {
60
+ (state, prev) => {
61
61
  const withTokenOverride = {
62
62
  ...(prev as object),
63
63
  ...(tokenOverride as object),
@@ -68,7 +68,7 @@ const mergeBubbleStyleOverwrite = <TStyle extends StyleProp<ViewStyle> | object>
68
68
  }
69
69
 
70
70
  if (typeof userOverwrite === 'function') {
71
- return userOverwrite(withTokenOverride, state)
71
+ return userOverwrite(state, withTokenOverride)
72
72
  }
73
73
 
74
74
  return {
@@ -196,16 +196,16 @@ export const ChatAttachmentMessageBubble = ({
196
196
  accessibilityLabel={downloadLabel}
197
197
  disabled={onDownload == null}
198
198
  onPress={onDownload}
199
- containerStyle={(_, pressableState) => (
199
+ style={(pressableState) => (
200
200
  contentResolvers.container(pressableState, contentContainerStyle)
201
201
  )}
202
- stateLayerStyle={(_, pressableState) => (
202
+ stateLayerStyle={(pressableState) => (
203
203
  contentResolvers.stateLayer(pressableState)
204
204
  )}
205
- textStyle={(_, pressableState) => (
205
+ textStyle={(pressableState) => (
206
206
  contentResolvers.text(pressableState)
207
207
  )}
208
- iconStyle={(_, pressableState) => (
208
+ iconStyle={(pressableState) => (
209
209
  contentResolvers.icon(pressableState)
210
210
  )}
211
211
  >
@@ -8,9 +8,7 @@ import {
8
8
  } from 'react'
9
9
  import {
10
10
  View,
11
- type PressableProps,
12
- type StyleProp,
13
- type ViewStyle
11
+ type PressableProps
14
12
  } from 'react-native'
15
13
  import { HightideIconRegistry } from '../../icons/HightideIconRegistry'
16
14
  import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
@@ -46,8 +44,7 @@ export type ChatConversationRowProps = Omit<PressableProps, 'children' | 'style'
46
44
  unreadCount?: number,
47
45
  isSelected?: boolean,
48
46
  sentIndicator?: ChatConversationSentIndicator,
49
- style?: StyleProp<ViewStyle>,
50
- rowStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
47
+ style?: StyleOverwrite<PressableState, PressableContainerStyle>,
51
48
  contentContainerStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowContentContainerStyle>,
52
49
  headerRowStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowHeaderRowStyle>,
53
50
  messageRowStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowMessageRowStyle>,
@@ -83,7 +80,6 @@ export const ChatConversationRow = ({
83
80
  sentIndicator,
84
81
  disabled,
85
82
  style,
86
- rowStyle,
87
83
  contentContainerStyle,
88
84
  headerRowStyle,
89
85
  messageRowStyle,
@@ -141,28 +137,28 @@ export const ChatConversationRow = ({
141
137
 
142
138
  return cloneElement(avatarElement, {
143
139
  size: avatarSize,
144
- avatarStyle: (_, avatarState) => avatarTheme.container(
140
+ avatarStyle: (avatarState) => avatarTheme.container(
145
141
  {
146
142
  ...avatarState,
147
143
  size: avatarSize,
148
144
  },
149
145
  avatarStyle ?? avatarElement.props.avatarStyle
150
146
  ),
151
- imageStyle: (_, avatarState) => avatarTheme.image(
147
+ imageStyle: (avatarState) => avatarTheme.image(
152
148
  {
153
149
  ...avatarState,
154
150
  size: avatarSize,
155
151
  },
156
152
  avatarElement.props.imageStyle
157
153
  ),
158
- textStyle: (_, avatarState) => avatarTheme.text(
154
+ textStyle: (avatarState) => avatarTheme.text(
159
155
  {
160
156
  ...avatarState,
161
157
  size: avatarSize,
162
158
  },
163
159
  avatarElement.props.textStyle
164
160
  ),
165
- iconStyle: (_, avatarState) => avatarTheme.icon(
161
+ iconStyle: (avatarState) => avatarTheme.icon(
166
162
  {
167
163
  ...avatarState,
168
164
  size: avatarSize,
@@ -176,23 +172,22 @@ export const ChatConversationRow = ({
176
172
  <ThemedPressable
177
173
  {...props}
178
174
  disabled={disabled}
179
- style={style}
180
- containerStyle={(_, pressableState) => {
175
+ style={(pressableState) => {
181
176
  const state = resolveState(pressableState as PressableInteraction)
182
177
  return theme.components.chat.conversationRow.pressable(state).container(
183
178
  pressableState,
184
- rowStyle
179
+ style
185
180
  )
186
181
  }}
187
- stateLayerStyle={(_, pressableState) => {
182
+ stateLayerStyle={(pressableState) => {
188
183
  const state = resolveState(pressableState as PressableInteraction)
189
184
  return theme.components.chat.conversationRow.pressable(state).stateLayer(pressableState)
190
185
  }}
191
- textStyle={(_, pressableState) => {
186
+ textStyle={(pressableState) => {
192
187
  const state = resolveState(pressableState as PressableInteraction)
193
188
  return theme.components.chat.conversationRow.pressable(state).text(pressableState)
194
189
  }}
195
- iconStyle={(_, pressableState) => {
190
+ iconStyle={(pressableState) => {
196
191
  const state = resolveState(pressableState as PressableInteraction)
197
192
  return theme.components.chat.conversationRow.pressable(state).icon(pressableState)
198
193
  }}
@@ -228,21 +223,23 @@ export const ChatConversationRow = ({
228
223
  )}
229
224
  </View>
230
225
  <View style={resolvedMessageRow}>
231
- {sentIndicator && (
232
- <ThemedIcon
233
- icon={sentIndicatorIcon}
234
- size={resolvedSentIndicator.size}
235
- strokeWidth={resolvedSentIndicator.strokeWidth}
236
- color={resolvedSentIndicator.color}
237
- />
238
- )}
239
- {preview != null && (
240
- typeof preview === 'string' || typeof preview === 'number' ? (
241
- <ThemedText style={resolvedPreview} numberOfLines={1}>{preview}</ThemedText>
242
- ) : (
243
- preview
244
- )
245
- )}
226
+ <View style={{ flexDirection: 'row', alignItems: 'center', flex: 1, gap: theme.spacing.xs /* TODO replace this with a theme style */ }}>
227
+ {sentIndicator && (
228
+ <ThemedIcon
229
+ icon={sentIndicatorIcon}
230
+ size={resolvedSentIndicator.size}
231
+ strokeWidth={resolvedSentIndicator.strokeWidth}
232
+ color={resolvedSentIndicator.color}
233
+ />
234
+ )}
235
+ {preview != null && (
236
+ typeof preview === 'string' || typeof preview === 'number' ? (
237
+ <ThemedText style={resolvedPreview} numberOfLines={1}>{preview}</ThemedText>
238
+ ) : (
239
+ preview
240
+ )
241
+ )}
242
+ </View>
246
243
  {isUnread && (
247
244
  <View style={unreadBadge}>
248
245
  <ThemedText style={unreadBadgeText}>{unreadCount}</ThemedText>
@@ -20,6 +20,7 @@ import type {
20
20
  ChatMessageComposerStyle
21
21
  } from '../../theme/types/components/chat'
22
22
  import type { StyleOverwrite } from '../../theme/types/resolver'
23
+ import { StyleAdapterUtils } from '../../theme'
23
24
 
24
25
  export type ChatMessageComposerProps = Omit<ViewProps, 'style'> & {
25
26
  value?: string,
@@ -108,8 +109,8 @@ export const ChatMessageComposer = ({
108
109
  disabled={disabled || !(value ?? '').trim()}
109
110
  size="sm"
110
111
  onPress={send}
111
- containerStyle={(prev) => ({ ...prev, borderRadius: 999 })}
112
- stateLayerStyle={(prev) => ({ ...prev, borderRadius: 999 })}
112
+ style={{ ...StyleAdapterUtils.borderRadius({ type: 'all', value: 999 }) }}
113
+ stateLayerStyle={{ ...StyleAdapterUtils.borderRadius({ type: 'all', value: 999 }) }}
113
114
  />
114
115
  </View>
115
116
  </View>
@@ -2,7 +2,6 @@ import {
2
2
  useMemo,
3
3
  type ReactNode
4
4
  } from 'react'
5
- import type { StyleProp, ViewStyle } from 'react-native'
6
5
 
7
6
  import { useTheme } from '../../global-contexts/theme/ThemeContext'
8
7
  import {
@@ -25,8 +24,7 @@ export type ChatQuickReplyChipProps = Omit<
25
24
  > & {
26
25
  isActive?: boolean,
27
26
  children?: ReactNode,
28
- style?: StyleProp<ViewStyle>,
29
- containerStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
27
+ style?: StyleOverwrite<PressableState, PressableContainerStyle>,
30
28
  textStyle?: StyleOverwrite<PressableState, PressableTextStyle>,
31
29
  iconStyle?: StyleOverwrite<PressableState, PressableIconStyle>,
32
30
  }
@@ -36,7 +34,6 @@ export const ChatQuickReplyChip = ({
36
34
  children,
37
35
  disabled,
38
36
  style,
39
- containerStyle,
40
37
  textStyle,
41
38
  iconStyle,
42
39
  ...props
@@ -52,17 +49,16 @@ export const ChatQuickReplyChip = ({
52
49
  <ThemedPressable
53
50
  {...props}
54
51
  disabled={disabled}
55
- style={style}
56
- containerStyle={(_, pressableState) => (
57
- pressableResolvers.container(pressableState, containerStyle)
52
+ style={(pressableState) => (
53
+ pressableResolvers.container(pressableState, style)
58
54
  )}
59
- stateLayerStyle={(_, pressableState) => (
55
+ stateLayerStyle={(pressableState) => (
60
56
  pressableResolvers.stateLayer(pressableState)
61
57
  )}
62
- textStyle={(_, pressableState) => (
58
+ textStyle={(pressableState) => (
63
59
  pressableResolvers.text(pressableState, textStyle)
64
60
  )}
65
- iconStyle={(_, pressableState) => (
61
+ iconStyle={(pressableState) => (
66
62
  pressableResolvers.icon(pressableState, iconStyle)
67
63
  )}
68
64
  >
@@ -114,44 +114,44 @@ export const ChatThreadHeader = ({
114
114
  <ThemedPressable
115
115
  onPress={onPress}
116
116
  disabled={disabled}
117
- containerStyle={(_, pressableState) => (
117
+ style={(pressableState) => (
118
118
  pressableResolvers.container(pressableState, pressableContainerStyle)
119
119
  )}
120
- stateLayerStyle={(_, pressableState) => (
120
+ stateLayerStyle={(pressableState) => (
121
121
  pressableResolvers.stateLayer(pressableState)
122
122
  )}
123
- textStyle={(_, pressableState) => (
123
+ textStyle={(pressableState) => (
124
124
  pressableResolvers.text(pressableState)
125
125
  )}
126
- iconStyle={(_, pressableState) => (
126
+ iconStyle={(pressableState) => (
127
127
  pressableResolvers.icon(pressableState)
128
128
  )}
129
129
  >
130
130
  <Avatar
131
131
  {...resolvedAvatar}
132
132
  size={avatarSize}
133
- avatarStyle={(_, avatarState) => avatarTheme.container(
133
+ avatarStyle={(avatarState) => avatarTheme.container(
134
134
  {
135
135
  ...avatarState,
136
136
  size: avatarSize,
137
137
  },
138
138
  resolvedAvatar.avatarStyle
139
139
  )}
140
- imageStyle={(_, avatarState) => avatarTheme.image(
140
+ imageStyle={(avatarState) => avatarTheme.image(
141
141
  {
142
142
  ...avatarState,
143
143
  size: avatarSize,
144
144
  },
145
145
  resolvedAvatar.imageStyle
146
146
  )}
147
- textStyle={(_, avatarState) => avatarTheme.text(
147
+ textStyle={(avatarState) => avatarTheme.text(
148
148
  {
149
149
  ...avatarState,
150
150
  size: avatarSize,
151
151
  },
152
152
  resolvedAvatar.textStyle
153
153
  )}
154
- iconStyle={(_, avatarState) => avatarTheme.icon(
154
+ iconStyle={(avatarState) => avatarTheme.icon(
155
155
  {
156
156
  ...avatarState,
157
157
  size: avatarSize,
@@ -2,9 +2,7 @@ import { Fragment, forwardRef } from 'react'
2
2
  import {
3
3
  Pressable,
4
4
  View,
5
- type PressableProps,
6
- type StyleProp,
7
- type ViewStyle
5
+ type PressableProps
8
6
  } from 'react-native'
9
7
 
10
8
  import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
@@ -13,7 +11,7 @@ import type { ComponentSize, ButtonVariant } from '@helpwave/hightide-design/sem
13
11
  import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
14
12
  import { useDebugContext } from '../../global-contexts/debug'
15
13
  import { useTheme } from '../../global-contexts/theme/ThemeContext'
16
- import type { IconComponent } from '../../icons/types'
14
+ import type { IconComponent, IconStyle } from '../../icons/types'
17
15
  import type {
18
16
  ButtonState,
19
17
  ButtonStyle,
@@ -41,10 +39,10 @@ export type ButtonProps = Omit<PressableProps, 'children' | 'style'> & {
41
39
  children: string,
42
40
  leadingIcon?: IconComponent,
43
41
  trailingIcon?: IconComponent,
44
- style?: StyleProp<ViewStyle>,
45
- containerStyle?: StyleOverwrite<ButtonState, ButtonStyle>,
42
+ style?: StyleOverwrite<ButtonState, ButtonStyle>,
46
43
  stateLayerStyle?: StyleOverwrite<ButtonState, ButtonStyle>,
47
44
  textStyle?: StyleOverwrite<ButtonState, ButtonTextStyle>,
45
+ iconStyle?: StyleOverwrite<ButtonState, IconStyle>,
48
46
  }
49
47
 
50
48
  type PressableInteraction = {
@@ -63,9 +61,9 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
63
61
  leadingIcon,
64
62
  trailingIcon,
65
63
  style,
66
- containerStyle,
67
64
  stateLayerStyle,
68
65
  textStyle,
66
+ iconStyle,
69
67
  hitSlop: providedHitSlop,
70
68
  onLayout: providedOnLayout,
71
69
  ...props
@@ -98,16 +96,13 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
98
96
  onLayout={onLayout}
99
97
  style={(pressableState) => {
100
98
  const state = resolveState(pressableState as PressableInteraction)
101
- return [
102
- theme.components.button.container(state, containerStyle),
103
- style,
104
- ]
99
+ return theme.components.button.container(state, style)
105
100
  }}
106
101
  >
107
102
  {(pressableState) => {
108
103
  const state = resolveState(pressableState as PressableInteraction)
109
104
  const resolvedText = theme.components.button.text(state, textStyle)
110
- const resolvedIcon = theme.components.button.icon(state)
105
+ const resolvedIcon = theme.components.button.icon(state, iconStyle)
111
106
 
112
107
  return (
113
108
  <Fragment>
@@ -2,9 +2,7 @@ import { Fragment, forwardRef } from 'react'
2
2
  import {
3
3
  Pressable,
4
4
  View,
5
- type PressableProps,
6
- type StyleProp,
7
- type ViewStyle
5
+ type PressableProps
8
6
  } from 'react-native'
9
7
  import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
10
8
  import type {
@@ -20,7 +18,7 @@ import type {
20
18
  IconButtonStyle
21
19
  } from '../../theme/types/components/iconButton'
22
20
  import type { StyleOverwrite } from '../../theme/types/resolver'
23
- import type { IconComponent } from '../../icons'
21
+ import type { IconComponent, IconStyle } from '../../icons'
24
22
  import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
25
23
  import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
26
24
  import { ThemedIcon } from '../visualization-and-display'
@@ -40,9 +38,9 @@ export type IconButtonProps = Omit<PressableProps, 'children' | 'style'> & {
40
38
  variant?: IconButtonVariant,
41
39
  icon: IconComponent,
42
40
  accessibilityLabel: string,
43
- style?: StyleProp<ViewStyle>,
44
- containerStyle?: StyleOverwrite<IconButtonState, IconButtonStyle>,
41
+ style?: StyleOverwrite<IconButtonState, IconButtonStyle>,
45
42
  stateLayerStyle?: StyleOverwrite<IconButtonState, IconButtonStyle>,
43
+ iconStyle?: StyleOverwrite<IconButtonState, IconStyle>,
46
44
  }
47
45
 
48
46
  type PressableInteraction = {
@@ -60,8 +58,8 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
60
58
  disabled,
61
59
  accessibilityLabel,
62
60
  style,
63
- containerStyle,
64
61
  stateLayerStyle,
62
+ iconStyle,
65
63
  hitSlop: providedHitSlop,
66
64
  onLayout: providedOnLayout,
67
65
  ...props
@@ -96,15 +94,12 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
96
94
  onLayout={onLayout}
97
95
  style={(pressableState) => {
98
96
  const state = resolveState(pressableState as PressableInteraction)
99
- return [
100
- theme.components.iconButton.container(state, containerStyle),
101
- style,
102
- ]
97
+ return theme.components.iconButton.container(state, style)
103
98
  }}
104
99
  >
105
100
  {(pressableState) => {
106
101
  const state = resolveState(pressableState as PressableInteraction)
107
- const resolvedIcon = theme.components.iconButton.icon(state)
102
+ const resolvedIcon = theme.components.iconButton.icon(state, iconStyle)
108
103
 
109
104
  return (
110
105
  <Fragment>
@@ -33,13 +33,13 @@ export const ThemedPressableUtil = {
33
33
  coloringColorVariants: ['normal', 'tonal', 'transparent'] as const satisfies readonly ColoringColorVariant[],
34
34
  }
35
35
 
36
- export type ThemedPressableProps = PressableProps & {
36
+ export type ThemedPressableProps = Omit<PressableProps, 'style'> & {
37
37
  size?: ThemedPressableSize,
38
38
  color?: ColorPairToken,
39
39
  coloringStyle?: ColoringStyle,
40
40
  coloringColorVariant?: ColoringColorVariant,
41
41
  hasAdditionalHorizontalPadding?: boolean,
42
- containerStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableStyle>,
42
+ style?: StyleOverwrite<ThemedPressableState, ThemedPressableStyle>,
43
43
  stateLayerStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableStyle>,
44
44
  iconStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableIconStyle>,
45
45
  textStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableTextStyle>,
@@ -61,7 +61,6 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
61
61
  hasAdditionalHorizontalPadding = false,
62
62
  disabled,
63
63
  style,
64
- containerStyle,
65
64
  stateLayerStyle,
66
65
  iconStyle,
67
66
  textStyle,
@@ -98,21 +97,18 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
98
97
  hitSlop={hitSlop}
99
98
  onLayout={onLayout}
100
99
  style={(pressableState) => {
101
- const state = resolveState(pressableState as PressableInteraction)
102
- const resolvedStyle = typeof style === 'function' ? style(pressableState) : style
103
- return [
104
- theme.components.themedPressable.container(state, containerStyle),
105
- resolvedStyle,
106
- ]
100
+ const state = resolveState(pressableState)
101
+ return theme.components.themedPressable.container(state, style)
107
102
  }}
108
103
  >
109
104
  {(pressableState) => {
110
- const state = resolveState(pressableState as PressableInteraction)
105
+ const state = resolveState(pressableState)
111
106
  const resolvedText = theme.components.themedPressable.text(state, textStyle)
112
107
  const resolvedIcon = theme.components.themedPressable.icon(state, iconStyle)
113
108
  const resolvedChildren = typeof children === 'function'
114
109
  ? children(pressableState)
115
110
  : children
111
+ const backroundColor = theme.components.themedPressable.container(state, style).backgroundColor
116
112
 
117
113
  return (
118
114
  <Fragment>
@@ -128,6 +124,7 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
128
124
  />
129
125
  <ContentThemeOverrideProvider
130
126
  foreground={resolvedText.color}
127
+ background={backroundColor}
131
128
  textStyle={resolvedText}
132
129
  iconStyle={resolvedIcon}
133
130
  >
@@ -226,19 +226,19 @@ export const AvatarGroup = ({
226
226
  isGrouped
227
227
  groupIndex={index}
228
228
  ImageComponent={avatar.ImageComponent ?? ImageComponent}
229
- avatarStyle={(_, state) => avatarResolvers.container({
229
+ avatarStyle={(state) => avatarResolvers.container({
230
230
  ...state,
231
231
  ...avatarState,
232
232
  })}
233
- imageStyle={(_, state) => avatarResolvers.image({
233
+ imageStyle={(state) => avatarResolvers.image({
234
234
  ...state,
235
235
  ...avatarState,
236
236
  })}
237
- textStyle={(_, state) => avatarResolvers.text({
237
+ textStyle={(state) => avatarResolvers.text({
238
238
  ...state,
239
239
  ...avatarState,
240
240
  })}
241
- iconStyle={(_, state) => avatarResolvers.icon({
241
+ iconStyle={(state) => avatarResolvers.icon({
242
242
  ...state,
243
243
  ...avatarState,
244
244
  })}
@@ -294,10 +294,10 @@ export const AvatarWithStatus = ({
294
294
  {...avatarProps}
295
295
  size={size}
296
296
  color={color}
297
- avatarStyle={(_, state) => avatarResolvers.container(state, avatarStyle)}
298
- imageStyle={(_, state) => avatarResolvers.image(state, imageStyle)}
299
- textStyle={(_, state) => avatarResolvers.text(state, textStyle)}
300
- iconStyle={(_, state) => avatarResolvers.icon(state, iconStyle)}
297
+ avatarStyle={(state) => avatarResolvers.container(state, avatarStyle)}
298
+ imageStyle={(state) => avatarResolvers.image(state, imageStyle)}
299
+ textStyle={(state) => avatarResolvers.text(state, textStyle)}
300
+ iconStyle={(state) => avatarResolvers.icon(state, iconStyle)}
301
301
  />
302
302
  <View style={resolvedStatusDot} />
303
303
  </View>
@@ -82,6 +82,7 @@ export const Chip = ({
82
82
  >
83
83
  <ContentThemeOverrideProvider
84
84
  foreground={resolvedTextStyle.color}
85
+ background={resolvedChipStyle.backgroundColor}
85
86
  textStyle={resolvedTextStyle}
86
87
  iconStyle={resolvedIconStyle}
87
88
  >
@@ -1,3 +1,5 @@
1
+ import type {
2
+ ColorValue } from 'react-native'
1
3
  import {
2
4
  View,
3
5
  type ViewProps
@@ -16,7 +18,7 @@ export type ThemedIconAppearance = Appearance
16
18
  export type ThemedIconProps = Omit<ViewProps, 'children'> & {
17
19
  icon: IconComponent,
18
20
  size?: IconSize | number,
19
- color?: string,
21
+ color?: ColorValue,
20
22
  strokeWidth?: number,
21
23
  appearance?: ThemedIconAppearance,
22
24
  }
@@ -8,6 +8,7 @@ import type { IconStyle } from '../../icons'
8
8
 
9
9
  export type ContentThemeContextValue = {
10
10
  foreground: ColorValue,
11
+ background: ColorValue,
11
12
  textStyle: TextStyle,
12
13
  iconStyle: IconStyle,
13
14
  }
@@ -16,14 +16,16 @@ export type ContentThemeRootProviderProps = PropsWithChildren & ContentThemeCont
16
16
  export const ContentThemeRootProvider = ({
17
17
  children,
18
18
  foreground,
19
+ background,
19
20
  textStyle,
20
21
  iconStyle,
21
22
  }: ContentThemeRootProviderProps) => {
22
23
  const value = useMemo((): ContentThemeContextValue => ({
23
24
  foreground,
25
+ background,
24
26
  textStyle,
25
27
  iconStyle,
26
- }), [foreground, textStyle, iconStyle])
28
+ }), [foreground, background, textStyle, iconStyle])
27
29
 
28
30
  return (
29
31
  <ContentThemeContext.Provider value={value}>
@@ -32,7 +34,7 @@ export const ContentThemeRootProvider = ({
32
34
  )
33
35
  }
34
36
 
35
- type ForegroundOverride =
37
+ type ColorOverride =
36
38
  | ColorValue
37
39
  | ((prev: ColorValue) => ColorValue)
38
40
 
@@ -45,38 +47,53 @@ type IconStyleOverride =
45
47
  | ((prev: IconStyle, foreground: ColorValue) => IconStyle)
46
48
 
47
49
  export type ContentThemeOverrideProviderProps = PropsWithChildren & {
48
- foreground?: ForegroundOverride,
50
+ foreground?: ColorOverride,
51
+ background?: ColorOverride,
49
52
  textStyle?: TextStyleOverride,
50
53
  iconStyle?: IconStyleOverride,
54
+ isKeepingTextColor?: boolean,
55
+ isKeepingIconColor?: boolean,
51
56
  }
52
57
 
53
58
  export const ContentThemeOverrideProvider = ({
54
59
  children,
55
60
  foreground: foregroundOverride,
61
+ background: backroundOverride,
56
62
  textStyle: textStyleOverride,
57
63
  iconStyle: iconStyleOverride,
64
+ isKeepingIconColor = false,
65
+ isKeepingTextColor = false,
58
66
  }: ContentThemeOverrideProviderProps) => {
59
67
  const parent = useContentTheme()
60
68
 
61
69
  const value = useMemo((): ContentThemeContextValue => {
62
- const foreground = typeof foregroundOverride === 'function'
70
+ const newForeground = typeof foregroundOverride === 'function'
63
71
  ? foregroundOverride(parent.foreground)
64
- : foregroundOverride ?? parent.foreground
72
+ : foregroundOverride
73
+
74
+ const newBackground = typeof backroundOverride === 'function'
75
+ ? backroundOverride(parent.background)
76
+ : backroundOverride
65
77
 
66
78
  const textStyle = typeof textStyleOverride === 'function'
67
- ? textStyleOverride(parent.textStyle, foreground)
79
+ ? textStyleOverride(parent.textStyle, parent.foreground)
68
80
  : textStyleOverride ?? parent.textStyle
69
81
 
82
+ if(!isKeepingTextColor && newForeground !== undefined) textStyle['color'] = newForeground
83
+
70
84
  const iconStyle = typeof iconStyleOverride === 'function'
71
- ? iconStyleOverride(parent.iconStyle, foreground)
85
+ ? iconStyleOverride(parent.iconStyle, parent.foreground)
72
86
  : iconStyleOverride ?? parent.iconStyle
73
87
 
88
+ if(!isKeepingIconColor && newForeground !== undefined) iconStyle['color'] = newForeground
89
+
74
90
  return {
75
- foreground,
91
+ foreground: newForeground ?? parent.foreground,
92
+ background: newBackground ?? parent.background,
76
93
  textStyle,
77
94
  iconStyle,
78
95
  }
79
- }, [parent, foregroundOverride, textStyleOverride, iconStyleOverride])
96
+ }, [parent, foregroundOverride, textStyleOverride, iconStyleOverride, backroundOverride, isKeepingTextColor, isKeepingIconColor])
80
97
 
81
98
  return (
82
99
  <ContentThemeContext.Provider value={value}>
@@ -1,8 +1,9 @@
1
1
  import type { ComponentType } from 'react'
2
+ import type { ColorValue } from 'react-native'
2
3
 
3
4
  export type IconStyle = {
4
5
  size?: number,
5
- color?: string,
6
+ color?: ColorValue,
6
7
  strokeWidth?: number,
7
8
  }
8
9
 
@@ -1,6 +1,8 @@
1
- import type {
2
- TextStyle,
3
- ViewStyle
1
+ import {
2
+ StyleSheet,
3
+ type StyleProp,
4
+ type TextStyle,
5
+ type ViewStyle
4
6
  } from 'react-native'
5
7
 
6
8
  import type {
@@ -24,6 +26,36 @@ import {
24
26
  import type { ShadowToken } from '@helpwave/hightide-design/theme-tokens'
25
27
  import type { IconStyle } from '../../icons'
26
28
 
29
+ function getStyleProperty<
30
+ T extends ViewStyle,
31
+ K extends keyof T
32
+ >(
33
+ style: StyleProp<T>,
34
+ property: K
35
+ ): T[K] {
36
+ if (style == null) {
37
+ return undefined as T[K]
38
+ }
39
+
40
+ if (Array.isArray(style)) {
41
+ for (let i = style.length - 1; i >= 0; i--) {
42
+ const value = getStyleProperty(
43
+ style[i] as StyleProp<T>,
44
+ property
45
+ )
46
+
47
+ if (value !== undefined) {
48
+ return value
49
+ }
50
+ }
51
+
52
+ return undefined as T[K]
53
+ }
54
+
55
+ const flattened = StyleSheet.flatten(style) as T
56
+ return flattened[property]
57
+ }
58
+
27
59
  type OptionalViewStyle<K extends keyof ViewStyle> = {
28
60
  [P in K]?: ViewStyle[P]
29
61
  }
@@ -144,7 +176,6 @@ const alignContentStyleAdapter = (
144
176
  const borderRadiusStyleAdapter = (
145
177
  borderRadius?: BorderRadiusToken
146
178
  ): OptionalViewStyle<
147
- | 'borderRadius'
148
179
  | 'borderTopLeftRadius'
149
180
  | 'borderTopRightRadius'
150
181
  | 'borderBottomLeftRadius'
@@ -156,16 +187,14 @@ const borderRadiusStyleAdapter = (
156
187
 
157
188
  if (borderRadius.type === 'all') {
158
189
  return {
159
- borderRadius: borderRadius.value,
160
- borderTopLeftRadius: undefined,
161
- borderTopRightRadius: undefined,
162
- borderBottomLeftRadius: undefined,
163
- borderBottomRightRadius: undefined,
190
+ borderTopLeftRadius: borderRadius.value,
191
+ borderTopRightRadius: borderRadius.value,
192
+ borderBottomLeftRadius: borderRadius.value,
193
+ borderBottomRightRadius: borderRadius.value,
164
194
  }
165
195
  }
166
196
 
167
197
  return {
168
- borderRadius: undefined,
169
198
  borderTopLeftRadius: borderRadius.topLeft,
170
199
  borderTopRightRadius: borderRadius.topRight,
171
200
  borderBottomLeftRadius: borderRadius.bottomLeft,
@@ -428,6 +457,7 @@ export const StyleAdapterUtils = {
428
457
  container: containerStyleAdapter,
429
458
  text: textStyleAdapter,
430
459
  icon: iconStyleAdapter,
460
+ stylePropResolver: getStyleProperty
431
461
  }
432
462
 
433
463
  export type StyleAdapters = typeof StyleAdapterUtils
@@ -67,20 +67,14 @@ export const toChatConversationRowThemeResolvers: ComponentThemeResolver<ChatCon
67
67
  const resolvePressable = (pressableState: PressableState) => componentTokens.pressable({
68
68
  themeTokens,
69
69
  semanticResolvers: semanticTokens,
70
- overrides: {
71
- size: pressableOverrides.overrides?.size,
72
- color: pressableOverrides.overrides?.color,
73
- coloringStyle: pressableOverrides.overrides?.coloringStyle,
74
- coloringColorVariant: pressableOverrides.overrides?.coloringColorVariant,
75
- hasAdditionalHorizontalPadding: pressableOverrides.overrides?.hasAdditionalHorizontalPadding,
76
- },
70
+ overrides: pressableOverrides.overrides ?? {},
77
71
  state: toPressableInteractionState(pressableState),
78
72
  })
79
73
 
80
74
  return {
81
75
  container: createStyleResolver((pressableState: PressableState): PressableContainerStyle => ({
82
76
  ...StyleAdapterUtils.container(resolvePressable(pressableState).container),
83
- ...StyleAdapterUtils.container(pressableOverrides.container = {}),
77
+ ...StyleAdapterUtils.container(pressableOverrides.container ?? {}),
84
78
  })),
85
79
  stateLayer: createStyleResolver((pressableState: PressableState): PressableStateLayerStyle => ({
86
80
  ...StyleAdapterUtils.container(resolvePressable(pressableState).stateLayer),
@@ -89,15 +83,15 @@ export const toChatConversationRowThemeResolvers: ComponentThemeResolver<ChatCon
89
83
  right: 0,
90
84
  bottom: 0,
91
85
  left: 0,
92
- ...StyleAdapterUtils.container(pressableOverrides.stateLayer = {}),
86
+ ...StyleAdapterUtils.container(pressableOverrides.stateLayer ?? {}),
93
87
  })),
94
88
  text: createStyleResolver((pressableState: PressableState): PressableTextStyle => ({
95
89
  ...StyleAdapterUtils.text(resolvePressable(pressableState).text),
96
- ...StyleAdapterUtils.text(pressableOverrides.text = {}),
90
+ ...StyleAdapterUtils.text(pressableOverrides.text ?? {}),
97
91
  })),
98
92
  icon: createValueResolver((pressableState: PressableState): PressableIconStyle => ({
99
93
  ...StyleAdapterUtils.icon(resolvePressable(pressableState).icon),
100
- ...StyleAdapterUtils.icon(pressableOverrides.icon = {}),
94
+ ...StyleAdapterUtils.icon(pressableOverrides.icon ?? {}),
101
95
  })),
102
96
  }
103
97
  }),
@@ -41,7 +41,7 @@ export const toPressableInteractionState = (
41
41
  }
42
42
 
43
43
  export type StyleOverwrite<TState, TStyle> =
44
- TStyle | ((prev: TStyle, state: TState) => TStyle)
44
+ TStyle | ((state: TState, prev: TStyle) => TStyle)
45
45
 
46
46
  export type StyleResolverFunction<TState, TStyle> = (
47
47
  props: TState,
@@ -67,7 +67,7 @@ export const createStyleResolver = <TState, TStyle>(
67
67
  }
68
68
 
69
69
  if (typeof overwrite === 'function') {
70
- return (overwrite as (prev: TStyle, state: TState) => TStyle)(base, props)
70
+ return (overwrite as (state: TState, prev: TStyle) => TStyle)(props, base)
71
71
  }
72
72
 
73
73
  return [base, overwrite] as TStyle
@@ -91,7 +91,7 @@ export const createValueResolver = <TState, TValue>(
91
91
  }
92
92
 
93
93
  if (typeof overwrite === 'function') {
94
- return (overwrite as (prev: TValue, state: TState) => TValue)(base, props)
94
+ return (overwrite as (state: TState, prev: TValue) => TValue)(props, base)
95
95
  }
96
96
 
97
97
  return overwrite