@helpwave/hightide-native 0.3.2 → 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 +3 -3
- package/src/components/chat/ChatAttachmentMessageBubble.tsx +6 -6
- package/src/components/chat/ChatConversationRow.tsx +28 -31
- package/src/components/chat/ChatMessageComposer.tsx +3 -2
- package/src/components/chat/ChatQuickReplyChip.tsx +6 -10
- package/src/components/chat/ChatThreadHeader.tsx +8 -8
- package/src/components/user-interaction/Button.tsx +7 -12
- package/src/components/user-interaction/IconButton.tsx +7 -12
- package/src/components/user-interaction/ThemedPressable.tsx +7 -10
- package/src/components/visualization-and-display/Avatar.tsx +8 -8
- package/src/components/visualization-and-display/Chip.tsx +1 -0
- package/src/components/visualization-and-display/ThemedIcon.tsx +3 -1
- package/src/global-contexts/content-theme/ContentThemeContext.ts +1 -0
- package/src/global-contexts/content-theme/ContentThemeProvider.tsx +26 -9
- package/src/icons/types.ts +2 -1
- package/src/theme/adapters/style-adapter-utils.ts +40 -10
- package/src/theme/resolvers/chat/conversation-row.ts +5 -11
- package/src/theme/types/resolver.ts +3 -3
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
12
|
"license": "AGPL-3.0-only",
|
|
13
|
-
"version": "0.
|
|
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-
|
|
47
|
-
"@helpwave/hightide-
|
|
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
|
-
(
|
|
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(
|
|
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
|
-
|
|
199
|
+
style={(pressableState) => (
|
|
200
200
|
contentResolvers.container(pressableState, contentContainerStyle)
|
|
201
201
|
)}
|
|
202
|
-
stateLayerStyle={(
|
|
202
|
+
stateLayerStyle={(pressableState) => (
|
|
203
203
|
contentResolvers.stateLayer(pressableState)
|
|
204
204
|
)}
|
|
205
|
-
textStyle={(
|
|
205
|
+
textStyle={(pressableState) => (
|
|
206
206
|
contentResolvers.text(pressableState)
|
|
207
207
|
)}
|
|
208
|
-
iconStyle={(
|
|
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?:
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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={
|
|
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
|
-
|
|
179
|
+
style
|
|
185
180
|
)
|
|
186
181
|
}}
|
|
187
|
-
stateLayerStyle={(
|
|
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={(
|
|
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={(
|
|
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
|
-
{
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
112
|
-
stateLayerStyle={
|
|
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?:
|
|
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={
|
|
56
|
-
|
|
57
|
-
pressableResolvers.container(pressableState, containerStyle)
|
|
52
|
+
style={(pressableState) => (
|
|
53
|
+
pressableResolvers.container(pressableState, style)
|
|
58
54
|
)}
|
|
59
|
-
stateLayerStyle={(
|
|
55
|
+
stateLayerStyle={(pressableState) => (
|
|
60
56
|
pressableResolvers.stateLayer(pressableState)
|
|
61
57
|
)}
|
|
62
|
-
textStyle={(
|
|
58
|
+
textStyle={(pressableState) => (
|
|
63
59
|
pressableResolvers.text(pressableState, textStyle)
|
|
64
60
|
)}
|
|
65
|
-
iconStyle={(
|
|
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
|
-
|
|
117
|
+
style={(pressableState) => (
|
|
118
118
|
pressableResolvers.container(pressableState, pressableContainerStyle)
|
|
119
119
|
)}
|
|
120
|
-
stateLayerStyle={(
|
|
120
|
+
stateLayerStyle={(pressableState) => (
|
|
121
121
|
pressableResolvers.stateLayer(pressableState)
|
|
122
122
|
)}
|
|
123
|
-
textStyle={(
|
|
123
|
+
textStyle={(pressableState) => (
|
|
124
124
|
pressableResolvers.text(pressableState)
|
|
125
125
|
)}
|
|
126
|
-
iconStyle={(
|
|
126
|
+
iconStyle={(pressableState) => (
|
|
127
127
|
pressableResolvers.icon(pressableState)
|
|
128
128
|
)}
|
|
129
129
|
>
|
|
130
130
|
<Avatar
|
|
131
131
|
{...resolvedAvatar}
|
|
132
132
|
size={avatarSize}
|
|
133
|
-
avatarStyle={(
|
|
133
|
+
avatarStyle={(avatarState) => avatarTheme.container(
|
|
134
134
|
{
|
|
135
135
|
...avatarState,
|
|
136
136
|
size: avatarSize,
|
|
137
137
|
},
|
|
138
138
|
resolvedAvatar.avatarStyle
|
|
139
139
|
)}
|
|
140
|
-
imageStyle={(
|
|
140
|
+
imageStyle={(avatarState) => avatarTheme.image(
|
|
141
141
|
{
|
|
142
142
|
...avatarState,
|
|
143
143
|
size: avatarSize,
|
|
144
144
|
},
|
|
145
145
|
resolvedAvatar.imageStyle
|
|
146
146
|
)}
|
|
147
|
-
textStyle={(
|
|
147
|
+
textStyle={(avatarState) => avatarTheme.text(
|
|
148
148
|
{
|
|
149
149
|
...avatarState,
|
|
150
150
|
size: avatarSize,
|
|
151
151
|
},
|
|
152
152
|
resolvedAvatar.textStyle
|
|
153
153
|
)}
|
|
154
|
-
iconStyle={(
|
|
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?:
|
|
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?:
|
|
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
|
-
|
|
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
|
|
102
|
-
|
|
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
|
|
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={(
|
|
229
|
+
avatarStyle={(state) => avatarResolvers.container({
|
|
230
230
|
...state,
|
|
231
231
|
...avatarState,
|
|
232
232
|
})}
|
|
233
|
-
imageStyle={(
|
|
233
|
+
imageStyle={(state) => avatarResolvers.image({
|
|
234
234
|
...state,
|
|
235
235
|
...avatarState,
|
|
236
236
|
})}
|
|
237
|
-
textStyle={(
|
|
237
|
+
textStyle={(state) => avatarResolvers.text({
|
|
238
238
|
...state,
|
|
239
239
|
...avatarState,
|
|
240
240
|
})}
|
|
241
|
-
iconStyle={(
|
|
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={(
|
|
298
|
-
imageStyle={(
|
|
299
|
-
textStyle={(
|
|
300
|
-
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>
|
|
@@ -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?:
|
|
21
|
+
color?: ColorValue,
|
|
20
22
|
strokeWidth?: number,
|
|
21
23
|
appearance?: ThemedIconAppearance,
|
|
22
24
|
}
|
|
@@ -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
|
|
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?:
|
|
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
|
|
70
|
+
const newForeground = typeof foregroundOverride === 'function'
|
|
63
71
|
? foregroundOverride(parent.foreground)
|
|
64
|
-
: foregroundOverride
|
|
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}>
|
package/src/icons/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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 | ((
|
|
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 (
|
|
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 (
|
|
94
|
+
return (overwrite as (state: TState, prev: TValue) => TValue)(props, base)
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
return overwrite
|