@helpwave/hightide-native 0.2.0 → 0.3.1
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 +2 -2
- package/src/components/chat/ChatConversationRow.tsx +127 -27
- package/src/components/chat/ChatThreadHeader.tsx +88 -48
- package/src/components/user-interaction/MultiSelect.tsx +66 -38
- package/src/components/user-interaction/Select.tsx +4 -0
- package/src/components/user-interaction/Switch.tsx +7 -3
- package/src/global-contexts/HightideProvider.tsx +9 -17
- package/src/theme/adapters/index.ts +1 -4
- package/src/theme/adapters/style-adapter-utils.ts +433 -0
- package/src/theme/resolvers/avatar.ts +9 -10
- package/src/theme/resolvers/button.ts +6 -7
- package/src/theme/resolvers/card.ts +3 -2
- package/src/theme/resolvers/chat/attachment-message-bubble.ts +22 -38
- package/src/theme/resolvers/chat/conversation-list.ts +5 -4
- package/src/theme/resolvers/chat/conversation-row.ts +114 -14
- package/src/theme/resolvers/chat/date-divider.ts +4 -4
- package/src/theme/resolvers/chat/message-bubble.ts +9 -10
- package/src/theme/resolvers/chat/message-composer.ts +5 -6
- package/src/theme/resolvers/chat/message-list.ts +3 -2
- package/src/theme/resolvers/chat/quick-reply-chip.ts +9 -28
- package/src/theme/resolvers/chat/system-line.ts +5 -6
- package/src/theme/resolvers/chat/thread-header.ts +60 -12
- package/src/theme/resolvers/checkbox.ts +6 -6
- package/src/theme/resolvers/chip.ts +5 -6
- package/src/theme/resolvers/divider.ts +3 -3
- package/src/theme/resolvers/iconButton.ts +5 -5
- package/src/theme/resolvers/input.ts +12 -7
- package/src/theme/resolvers/listItem.ts +16 -17
- package/src/theme/resolvers/multiSelect.ts +23 -16
- package/src/theme/resolvers/searchBar.ts +14 -7
- package/src/theme/resolvers/select.ts +22 -15
- package/src/theme/resolvers/switch.ts +5 -4
- package/src/theme/resolvers/themedPressable.ts +6 -7
- package/src/theme/themes/createHightideTheme.ts +13 -4
- package/src/theme/types/components/chat.ts +54 -3
- package/src/theme/types/components/multiSelect.ts +1 -0
- package/src/theme/types/components/select.ts +1 -0
- package/src/theme/types/layout.ts +13 -7
- package/src/theme/types/semantics.ts +2 -1
- package/src/theme/types/theme.ts +40 -12
- package/src/theme/types/typography.ts +9 -4
- package/src/theme/adapters/container-adapter.ts +0 -323
- package/src/theme/adapters/defined.ts +0 -11
- package/src/theme/adapters/icon-style-adapter.ts +0 -10
- package/src/theme/adapters/text-style-adapter.ts +0 -16
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.3.1",
|
|
14
14
|
"type": "module",
|
|
15
15
|
"files": [
|
|
16
16
|
"src"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"lucide-react-native": "0.561.0",
|
|
46
|
-
"@helpwave/hightide-design": "0.
|
|
46
|
+
"@helpwave/hightide-design": "0.3.0",
|
|
47
47
|
"@helpwave/hightide-utils": "0.1.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
cloneElement,
|
|
2
3
|
Fragment,
|
|
4
|
+
isValidElement,
|
|
3
5
|
useMemo,
|
|
6
|
+
type ReactElement,
|
|
4
7
|
type ReactNode
|
|
5
8
|
} from 'react'
|
|
6
9
|
import {
|
|
@@ -14,14 +17,24 @@ import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
|
14
17
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
15
18
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
16
19
|
import type {
|
|
20
|
+
AvatarState,
|
|
21
|
+
AvatarStyle
|
|
22
|
+
} from '../../theme/types/components/avatar'
|
|
23
|
+
import type {
|
|
24
|
+
ChatConversationRowContentContainerStyle,
|
|
25
|
+
ChatConversationRowHeaderRowStyle,
|
|
26
|
+
ChatConversationRowMessageRowStyle,
|
|
17
27
|
ChatConversationRowPreviewStyle,
|
|
28
|
+
ChatConversationRowSentIndicatorStyle,
|
|
18
29
|
ChatConversationRowState,
|
|
19
|
-
ChatConversationRowStyle,
|
|
20
30
|
ChatConversationRowTimestampStyle,
|
|
21
|
-
ChatConversationRowTitleStyle
|
|
31
|
+
ChatConversationRowTitleStyle,
|
|
32
|
+
PressableContainerStyle,
|
|
33
|
+
PressableState
|
|
22
34
|
} from '../../theme/types/components/chat'
|
|
23
35
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
24
36
|
import { ThemedPressable } from '../user-interaction'
|
|
37
|
+
import type { AvatarProps } from '../visualization-and-display/Avatar'
|
|
25
38
|
|
|
26
39
|
export type ChatConversationSentIndicator = 'sent' | 'sentAndReceived'
|
|
27
40
|
|
|
@@ -34,10 +47,15 @@ export type ChatConversationRowProps = Omit<PressableProps, 'children' | 'style'
|
|
|
34
47
|
isSelected?: boolean,
|
|
35
48
|
sentIndicator?: ChatConversationSentIndicator,
|
|
36
49
|
style?: StyleProp<ViewStyle>,
|
|
37
|
-
rowStyle?: StyleOverwrite<
|
|
50
|
+
rowStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
|
|
51
|
+
contentContainerStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowContentContainerStyle>,
|
|
52
|
+
headerRowStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowHeaderRowStyle>,
|
|
53
|
+
messageRowStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowMessageRowStyle>,
|
|
38
54
|
titleStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowTitleStyle>,
|
|
39
55
|
timestampStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowTimestampStyle>,
|
|
40
56
|
previewStyle?: StyleOverwrite<ChatConversationRowState, ChatConversationRowPreviewStyle>,
|
|
57
|
+
sentIndicatorStyle?: StyleOverwrite<Record<string, never>, ChatConversationRowSentIndicatorStyle>,
|
|
58
|
+
avatarStyle?: StyleOverwrite<AvatarState, AvatarStyle>,
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
type PressableInteraction = {
|
|
@@ -47,6 +65,14 @@ type PressableInteraction = {
|
|
|
47
65
|
focusVisible?: boolean,
|
|
48
66
|
}
|
|
49
67
|
|
|
68
|
+
type AvatarElementProps = AvatarProps & {
|
|
69
|
+
avatarStyle?: AvatarProps['avatarStyle'],
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const toNumericSize = (value: unknown): number | undefined => (
|
|
73
|
+
typeof value === 'number' ? value : undefined
|
|
74
|
+
)
|
|
75
|
+
|
|
50
76
|
export const ChatConversationRow = ({
|
|
51
77
|
avatar,
|
|
52
78
|
title,
|
|
@@ -58,9 +84,14 @@ export const ChatConversationRow = ({
|
|
|
58
84
|
disabled,
|
|
59
85
|
style,
|
|
60
86
|
rowStyle,
|
|
87
|
+
contentContainerStyle,
|
|
88
|
+
headerRowStyle,
|
|
89
|
+
messageRowStyle,
|
|
61
90
|
titleStyle,
|
|
62
91
|
timestampStyle,
|
|
63
92
|
previewStyle,
|
|
93
|
+
sentIndicatorStyle,
|
|
94
|
+
avatarStyle,
|
|
64
95
|
...props
|
|
65
96
|
}: ChatConversationRowProps) => {
|
|
66
97
|
const { theme } = useTheme()
|
|
@@ -88,31 +119,101 @@ export const ChatConversationRow = ({
|
|
|
88
119
|
() => theme.components.chat.conversationRow.unreadBadgeText(staticState),
|
|
89
120
|
[theme, staticState]
|
|
90
121
|
)
|
|
91
|
-
const
|
|
92
|
-
() => theme.components.chat.conversationRow.sentIndicator(staticState)
|
|
122
|
+
const resolvedSentIndicator = useMemo(
|
|
123
|
+
() => theme.components.chat.conversationRow.sentIndicator(staticState, sentIndicatorStyle),
|
|
124
|
+
[theme, staticState, sentIndicatorStyle]
|
|
125
|
+
)
|
|
126
|
+
const avatarTheme = useMemo(
|
|
127
|
+
() => theme.components.chat.conversationRow.avatar(staticState),
|
|
93
128
|
[theme, staticState]
|
|
94
129
|
)
|
|
130
|
+
const avatarSize = useMemo(
|
|
131
|
+
() => toNumericSize(avatarTheme.container({}).width),
|
|
132
|
+
[avatarTheme]
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const resolvedAvatar = useMemo(() => {
|
|
136
|
+
if (!isValidElement(avatar) || avatarSize === undefined) {
|
|
137
|
+
return avatar
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const avatarElement = avatar as ReactElement<AvatarElementProps>
|
|
141
|
+
|
|
142
|
+
return cloneElement(avatarElement, {
|
|
143
|
+
size: avatarSize,
|
|
144
|
+
avatarStyle: (_, avatarState) => avatarTheme.container(
|
|
145
|
+
{
|
|
146
|
+
...avatarState,
|
|
147
|
+
size: avatarSize,
|
|
148
|
+
},
|
|
149
|
+
avatarStyle ?? avatarElement.props.avatarStyle
|
|
150
|
+
),
|
|
151
|
+
imageStyle: (_, avatarState) => avatarTheme.image(
|
|
152
|
+
{
|
|
153
|
+
...avatarState,
|
|
154
|
+
size: avatarSize,
|
|
155
|
+
},
|
|
156
|
+
avatarElement.props.imageStyle
|
|
157
|
+
),
|
|
158
|
+
textStyle: (_, avatarState) => avatarTheme.text(
|
|
159
|
+
{
|
|
160
|
+
...avatarState,
|
|
161
|
+
size: avatarSize,
|
|
162
|
+
},
|
|
163
|
+
avatarElement.props.textStyle
|
|
164
|
+
),
|
|
165
|
+
iconStyle: (_, avatarState) => avatarTheme.icon(
|
|
166
|
+
{
|
|
167
|
+
...avatarState,
|
|
168
|
+
size: avatarSize,
|
|
169
|
+
},
|
|
170
|
+
avatarElement.props.iconStyle
|
|
171
|
+
),
|
|
172
|
+
})
|
|
173
|
+
}, [avatar, avatarSize, avatarStyle, avatarTheme])
|
|
95
174
|
|
|
96
175
|
return (
|
|
97
176
|
<ThemedPressable
|
|
98
177
|
{...props}
|
|
99
178
|
disabled={disabled}
|
|
100
|
-
style={
|
|
179
|
+
style={style}
|
|
180
|
+
containerStyle={(_, pressableState) => {
|
|
101
181
|
const state = resolveState(pressableState as PressableInteraction)
|
|
102
|
-
return
|
|
182
|
+
return theme.components.chat.conversationRow.pressable(state).container(
|
|
183
|
+
pressableState,
|
|
184
|
+
rowStyle
|
|
185
|
+
)
|
|
186
|
+
}}
|
|
187
|
+
stateLayerStyle={(_, pressableState) => {
|
|
188
|
+
const state = resolveState(pressableState as PressableInteraction)
|
|
189
|
+
return theme.components.chat.conversationRow.pressable(state).stateLayer(pressableState)
|
|
190
|
+
}}
|
|
191
|
+
textStyle={(_, pressableState) => {
|
|
192
|
+
const state = resolveState(pressableState as PressableInteraction)
|
|
193
|
+
return theme.components.chat.conversationRow.pressable(state).text(pressableState)
|
|
194
|
+
}}
|
|
195
|
+
iconStyle={(_, pressableState) => {
|
|
196
|
+
const state = resolveState(pressableState as PressableInteraction)
|
|
197
|
+
return theme.components.chat.conversationRow.pressable(state).icon(pressableState)
|
|
103
198
|
}}
|
|
104
199
|
>
|
|
105
200
|
{(pressableState) => {
|
|
106
201
|
const state = resolveState(pressableState as PressableInteraction)
|
|
202
|
+
const resolvedContentContainer = theme.components.chat.conversationRow.contentContainer(
|
|
203
|
+
state,
|
|
204
|
+
contentContainerStyle
|
|
205
|
+
)
|
|
206
|
+
const resolvedHeaderRow = theme.components.chat.conversationRow.headerRow(state, headerRowStyle)
|
|
207
|
+
const resolvedMessageRow = theme.components.chat.conversationRow.messageRow(state, messageRowStyle)
|
|
107
208
|
const resolvedTitle = theme.components.chat.conversationRow.title(state, titleStyle)
|
|
108
209
|
const resolvedTimestamp = theme.components.chat.conversationRow.timestamp(state, timestampStyle)
|
|
109
210
|
const resolvedPreview = theme.components.chat.conversationRow.preview(state, previewStyle)
|
|
110
211
|
|
|
111
212
|
return (
|
|
112
213
|
<Fragment>
|
|
113
|
-
{
|
|
114
|
-
<View style={
|
|
115
|
-
<View style={
|
|
214
|
+
{resolvedAvatar}
|
|
215
|
+
<View style={resolvedContentContainer}>
|
|
216
|
+
<View style={resolvedHeaderRow}>
|
|
116
217
|
{typeof title === 'string' || typeof title === 'number' ? (
|
|
117
218
|
<ThemedText style={resolvedTitle} numberOfLines={1}>{title}</ThemedText>
|
|
118
219
|
) : (
|
|
@@ -126,23 +227,22 @@ export const ChatConversationRow = ({
|
|
|
126
227
|
)
|
|
127
228
|
)}
|
|
128
229
|
</View>
|
|
129
|
-
<View style={
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
</View>
|
|
230
|
+
<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
|
+
)}
|
|
146
246
|
{isUnread && (
|
|
147
247
|
<View style={unreadBadge}>
|
|
148
248
|
<ThemedText style={unreadBadgeText}>{unreadCount}</ThemedText>
|
|
@@ -15,11 +15,17 @@ import {
|
|
|
15
15
|
Avatar,
|
|
16
16
|
type AvatarProps
|
|
17
17
|
} from '../visualization-and-display/Avatar'
|
|
18
|
+
import {
|
|
19
|
+
ThemedPressable,
|
|
20
|
+
type ThemedPressableProps
|
|
21
|
+
} from '../user-interaction/ThemedPressable'
|
|
18
22
|
import type {
|
|
19
23
|
ChatThreadHeaderContentRowStyle,
|
|
20
24
|
ChatThreadHeaderStyle,
|
|
21
25
|
ChatThreadHeaderSubtitleStyle,
|
|
22
|
-
ChatThreadHeaderTitleStyle
|
|
26
|
+
ChatThreadHeaderTitleStyle,
|
|
27
|
+
PressableContainerStyle,
|
|
28
|
+
PressableState
|
|
23
29
|
} from '../../theme/types/components/chat'
|
|
24
30
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
25
31
|
|
|
@@ -29,11 +35,14 @@ export type ChatThreadHeaderProps = Omit<ViewProps, 'style'> & {
|
|
|
29
35
|
subtitle?: ReactNode,
|
|
30
36
|
leftActions?: ReactNode,
|
|
31
37
|
rightActions?: ReactNode,
|
|
38
|
+
onPress?: ThemedPressableProps['onPress'],
|
|
39
|
+
disabled?: boolean,
|
|
32
40
|
style?: StyleProp<ViewStyle>,
|
|
33
41
|
headerStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderStyle>,
|
|
34
42
|
contentRowStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderContentRowStyle>,
|
|
35
43
|
titleStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderTitleStyle>,
|
|
36
44
|
subtitleStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderSubtitleStyle>,
|
|
45
|
+
pressableContainerStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
export const ChatThreadHeader = ({
|
|
@@ -42,11 +51,14 @@ export const ChatThreadHeader = ({
|
|
|
42
51
|
subtitle,
|
|
43
52
|
leftActions,
|
|
44
53
|
rightActions,
|
|
54
|
+
onPress,
|
|
55
|
+
disabled,
|
|
45
56
|
style,
|
|
46
57
|
headerStyle,
|
|
47
58
|
contentRowStyle,
|
|
48
59
|
titleStyle,
|
|
49
60
|
subtitleStyle,
|
|
61
|
+
pressableContainerStyle,
|
|
50
62
|
...props
|
|
51
63
|
}: ChatThreadHeaderProps) => {
|
|
52
64
|
const { theme } = useTheme()
|
|
@@ -71,16 +83,26 @@ export const ChatThreadHeader = ({
|
|
|
71
83
|
() => theme.components.chat.threadHeader.subtitle(state, subtitleStyle),
|
|
72
84
|
[theme, state, subtitleStyle]
|
|
73
85
|
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}), [resolvedAvatar.size, resolvedAvatar.color])
|
|
86
|
+
const pressableResolvers = useMemo(
|
|
87
|
+
() => theme.components.chat.threadHeader.pressable(state),
|
|
88
|
+
[theme, state]
|
|
89
|
+
)
|
|
79
90
|
|
|
80
91
|
const avatarTheme = useMemo(
|
|
81
|
-
() => theme.components.chat.threadHeader.avatar(
|
|
82
|
-
|
|
92
|
+
() => theme.components.chat.threadHeader.avatar({
|
|
93
|
+
size: resolvedAvatar.size,
|
|
94
|
+
color: resolvedAvatar.color,
|
|
95
|
+
}),
|
|
96
|
+
[theme, resolvedAvatar.size, resolvedAvatar.color]
|
|
83
97
|
)
|
|
98
|
+
const avatarSize = useMemo(() => {
|
|
99
|
+
if (typeof resolvedAvatar.size === 'number' || typeof resolvedAvatar.size === 'string') {
|
|
100
|
+
return resolvedAvatar.size
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const width = avatarTheme.container({}).width
|
|
104
|
+
return typeof width === 'number' ? width : resolvedAvatar.size
|
|
105
|
+
}, [avatarTheme, resolvedAvatar.size])
|
|
84
106
|
|
|
85
107
|
return (
|
|
86
108
|
<View {...props} style={[resolvedHeaderStyle, style]}>
|
|
@@ -89,51 +111,69 @@ export const ChatThreadHeader = ({
|
|
|
89
111
|
{leftActions}
|
|
90
112
|
</View>
|
|
91
113
|
)}
|
|
92
|
-
<
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
size: resolvedAvatar.size,
|
|
98
|
-
},
|
|
99
|
-
resolvedAvatar.avatarStyle
|
|
114
|
+
<ThemedPressable
|
|
115
|
+
onPress={onPress}
|
|
116
|
+
disabled={disabled}
|
|
117
|
+
containerStyle={(_, pressableState) => (
|
|
118
|
+
pressableResolvers.container(pressableState, pressableContainerStyle)
|
|
100
119
|
)}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
...avatarState,
|
|
104
|
-
size: resolvedAvatar.size,
|
|
105
|
-
},
|
|
106
|
-
resolvedAvatar.imageStyle
|
|
120
|
+
stateLayerStyle={(_, pressableState) => (
|
|
121
|
+
pressableResolvers.stateLayer(pressableState)
|
|
107
122
|
)}
|
|
108
|
-
textStyle={(_,
|
|
109
|
-
|
|
110
|
-
...avatarState,
|
|
111
|
-
size: resolvedAvatar.size,
|
|
112
|
-
},
|
|
113
|
-
resolvedAvatar.textStyle
|
|
123
|
+
textStyle={(_, pressableState) => (
|
|
124
|
+
pressableResolvers.text(pressableState)
|
|
114
125
|
)}
|
|
115
|
-
iconStyle={(_,
|
|
116
|
-
|
|
117
|
-
...avatarState,
|
|
118
|
-
size: resolvedAvatar.size,
|
|
119
|
-
},
|
|
120
|
-
resolvedAvatar.iconStyle
|
|
126
|
+
iconStyle={(_, pressableState) => (
|
|
127
|
+
pressableResolvers.icon(pressableState)
|
|
121
128
|
)}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
>
|
|
130
|
+
<Avatar
|
|
131
|
+
{...resolvedAvatar}
|
|
132
|
+
size={avatarSize}
|
|
133
|
+
avatarStyle={(_, avatarState) => avatarTheme.container(
|
|
134
|
+
{
|
|
135
|
+
...avatarState,
|
|
136
|
+
size: avatarSize,
|
|
137
|
+
},
|
|
138
|
+
resolvedAvatar.avatarStyle
|
|
139
|
+
)}
|
|
140
|
+
imageStyle={(_, avatarState) => avatarTheme.image(
|
|
141
|
+
{
|
|
142
|
+
...avatarState,
|
|
143
|
+
size: avatarSize,
|
|
144
|
+
},
|
|
145
|
+
resolvedAvatar.imageStyle
|
|
146
|
+
)}
|
|
147
|
+
textStyle={(_, avatarState) => avatarTheme.text(
|
|
148
|
+
{
|
|
149
|
+
...avatarState,
|
|
150
|
+
size: avatarSize,
|
|
151
|
+
},
|
|
152
|
+
resolvedAvatar.textStyle
|
|
153
|
+
)}
|
|
154
|
+
iconStyle={(_, avatarState) => avatarTheme.icon(
|
|
155
|
+
{
|
|
156
|
+
...avatarState,
|
|
157
|
+
size: avatarSize,
|
|
158
|
+
},
|
|
159
|
+
resolvedAvatar.iconStyle
|
|
160
|
+
)}
|
|
161
|
+
/>
|
|
162
|
+
<View style={resolvedContentRowStyle}>
|
|
163
|
+
{typeof title === 'string' || typeof title === 'number' ? (
|
|
164
|
+
<ThemedText style={resolvedTitleStyle} numberOfLines={1}>{title}</ThemedText>
|
|
132
165
|
) : (
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
166
|
+
title
|
|
167
|
+
)}
|
|
168
|
+
{subtitle != null && (
|
|
169
|
+
typeof subtitle === 'string' || typeof subtitle === 'number' ? (
|
|
170
|
+
<ThemedText style={resolvedSubtitleStyle} numberOfLines={1}>{subtitle}</ThemedText>
|
|
171
|
+
) : (
|
|
172
|
+
subtitle
|
|
173
|
+
)
|
|
174
|
+
)}
|
|
175
|
+
</View>
|
|
176
|
+
</ThemedPressable>
|
|
137
177
|
{rightActions != null && (
|
|
138
178
|
<View style={{ flexDirection: 'row', alignItems: 'center', flexShrink: 0 }}>
|
|
139
179
|
{rightActions}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMemo } from 'react'
|
|
1
|
+
import { Fragment, useMemo } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
FlatList,
|
|
4
4
|
Modal,
|
|
@@ -128,44 +128,72 @@ export const MultiSelect = ({
|
|
|
128
128
|
})
|
|
129
129
|
}}
|
|
130
130
|
>
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
131
|
+
{(pressableState) => {
|
|
132
|
+
const interaction = pressableState as {
|
|
133
|
+
pressed: boolean,
|
|
134
|
+
hovered?: boolean,
|
|
135
|
+
focused?: boolean,
|
|
136
|
+
focusVisible?: boolean,
|
|
137
|
+
}
|
|
138
|
+
const triggerState = {
|
|
139
|
+
...state,
|
|
140
|
+
isPressed: interaction.pressed,
|
|
141
|
+
isHovered: !!interaction.hovered,
|
|
142
|
+
isFocused: !!interaction.focused,
|
|
143
|
+
isFocusVisible: !!interaction.focusVisible,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<Fragment>
|
|
148
|
+
<View
|
|
149
|
+
pointerEvents="none"
|
|
150
|
+
style={multiSelectTheme.stateLayer(triggerState)}
|
|
151
|
+
/>
|
|
152
|
+
{selectedOptions.length > 0
|
|
153
|
+
? (
|
|
154
|
+
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 6, flex: 1 }}>
|
|
155
|
+
{selectedOptions.map((option) => (
|
|
156
|
+
<Chip key={option.id} size="md" color={color} variant="tonal">
|
|
157
|
+
<ThemedText>{option.label ?? option.id}</ThemedText>
|
|
158
|
+
{!state.isReadonly && (
|
|
159
|
+
<View
|
|
160
|
+
style={{
|
|
161
|
+
position: 'relative',
|
|
162
|
+
width: theme.icongraphy.sizes.sm,
|
|
163
|
+
}}
|
|
164
|
+
>
|
|
165
|
+
<IconButton
|
|
166
|
+
accessibilityLabel={translation('remove')}
|
|
167
|
+
size="sm"
|
|
168
|
+
color={theme.colors.negative}
|
|
169
|
+
variant="foreground"
|
|
170
|
+
disabled={!interactive}
|
|
171
|
+
onPress={() => multiSelect.toggleSelection(option.id, false)}
|
|
172
|
+
style={{
|
|
173
|
+
position: 'absolute',
|
|
174
|
+
left: '50%',
|
|
175
|
+
top: '50%',
|
|
176
|
+
transform: [
|
|
177
|
+
{ translateX: '-50%' },
|
|
178
|
+
{ translateY: '-50%' },
|
|
179
|
+
],
|
|
180
|
+
}}
|
|
181
|
+
icon={HightideIconRegistry.X}
|
|
182
|
+
/>
|
|
183
|
+
</View>
|
|
184
|
+
)}
|
|
185
|
+
</Chip>
|
|
186
|
+
))}
|
|
187
|
+
</View>
|
|
188
|
+
)
|
|
189
|
+
: (
|
|
190
|
+
<ThemedText style={multiSelectTheme.triggerText(triggerState)}>
|
|
191
|
+
{placeholder}
|
|
192
|
+
</ThemedText>
|
|
193
|
+
)}
|
|
194
|
+
</Fragment>
|
|
167
195
|
)
|
|
168
|
-
|
|
196
|
+
}}
|
|
169
197
|
</Pressable>
|
|
170
198
|
|
|
171
199
|
<Modal
|
|
@@ -149,6 +149,10 @@ export const Select = ({
|
|
|
149
149
|
|
|
150
150
|
return (
|
|
151
151
|
<Fragment>
|
|
152
|
+
<View
|
|
153
|
+
pointerEvents="none"
|
|
154
|
+
style={selectTheme.stateLayer(triggerState)}
|
|
155
|
+
/>
|
|
152
156
|
<ThemedText style={[selectTheme.triggerText(triggerState), { flex: 1 }]}>
|
|
153
157
|
{selectedLabel}
|
|
154
158
|
</ThemedText>
|
|
@@ -151,11 +151,15 @@ export const Switch = ({
|
|
|
151
151
|
const resolvedThumbActive = theme.components.switch.thumb(activeState, thumbStyle)
|
|
152
152
|
const trackWidth = toNumber(resolvedTrackStyle.width as string | number | undefined, 40)
|
|
153
153
|
const trackHeight = toNumber(resolvedTrackStyle.height as string | number | undefined, 28)
|
|
154
|
-
const
|
|
154
|
+
const fallbackBorderWidth = toNumber(resolvedTrackStyle.borderWidth, 0)
|
|
155
|
+
const trackBorderTop = toNumber(resolvedTrackStyle.borderTopWidth, fallbackBorderWidth)
|
|
156
|
+
const trackBorderRight = toNumber(resolvedTrackStyle.borderRightWidth, fallbackBorderWidth)
|
|
157
|
+
const trackBorderBottom = toNumber(resolvedTrackStyle.borderBottomWidth, fallbackBorderWidth)
|
|
158
|
+
const trackBorderLeft = toNumber(resolvedTrackStyle.borderLeftWidth, fallbackBorderWidth)
|
|
155
159
|
const thumbInactiveSize = toNumber(resolvedThumbInactive.width as string | number | undefined, 16)
|
|
156
160
|
const thumbActiveSize = toNumber(resolvedThumbActive.width as string | number | undefined, 20)
|
|
157
|
-
const trackInnerWidth = trackWidth -
|
|
158
|
-
const trackInnerHeight = trackHeight -
|
|
161
|
+
const trackInnerWidth = trackWidth - trackBorderLeft - trackBorderRight
|
|
162
|
+
const trackInnerHeight = trackHeight - trackBorderTop - trackBorderBottom
|
|
159
163
|
const thumbOffsetInactive = (trackInnerHeight - thumbInactiveSize) / 2
|
|
160
164
|
const thumbOffsetActive = trackInnerWidth - thumbActiveSize - (
|
|
161
165
|
(trackInnerHeight - thumbActiveSize) / 2
|
|
@@ -8,10 +8,6 @@ import { hightideTranslation } from '@helpwave/hightide-utils/i18n'
|
|
|
8
8
|
import { ArrayUtil } from '@helpwave/hightide-utils/utils'
|
|
9
9
|
|
|
10
10
|
import { HightideContext } from './HightideContext'
|
|
11
|
-
import {
|
|
12
|
-
DebugProvider,
|
|
13
|
-
type DebugProviderProps
|
|
14
|
-
} from './debug'
|
|
15
11
|
import {
|
|
16
12
|
LocalizationProvider,
|
|
17
13
|
type LocalizationProviderProps
|
|
@@ -31,7 +27,6 @@ export type HightideProviderProps = PropsWithChildren & {
|
|
|
31
27
|
theme?: Omit<ThemeProviderProps<HightideTheme>, 'children'>,
|
|
32
28
|
locale?: Omit<LocalizationProviderProps, 'children'>,
|
|
33
29
|
translation?: Omit<TranslationProviderProps, 'children' | 'locale'>,
|
|
34
|
-
debug?: Omit<DebugProviderProps, 'children'>,
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
const HightideContextBridge = ({ children }: PropsWithChildren) => {
|
|
@@ -55,7 +50,6 @@ export const HightideProvider = ({
|
|
|
55
50
|
theme,
|
|
56
51
|
locale,
|
|
57
52
|
translation,
|
|
58
|
-
debug,
|
|
59
53
|
}: HightideProviderProps) => {
|
|
60
54
|
const resolvedTranslations = useMemo(() => [
|
|
61
55
|
...ArrayUtil.resolveSingleOrArray(translation?.translation ?? []),
|
|
@@ -63,16 +57,14 @@ export const HightideProvider = ({
|
|
|
63
57
|
], [translation?.translation])
|
|
64
58
|
|
|
65
59
|
return (
|
|
66
|
-
<
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
</LocalizationProvider>
|
|
76
|
-
</DebugProvider>
|
|
60
|
+
<LocalizationProvider {...locale}>
|
|
61
|
+
<TranslationProvider {...translation} translation={resolvedTranslations}>
|
|
62
|
+
<ThemeProvider {...theme}>
|
|
63
|
+
<HightideContextBridge>
|
|
64
|
+
{children}
|
|
65
|
+
</HightideContextBridge>
|
|
66
|
+
</ThemeProvider>
|
|
67
|
+
</TranslationProvider>
|
|
68
|
+
</LocalizationProvider>
|
|
77
69
|
)
|
|
78
70
|
}
|