@helpwave/hightide-native 0.0.8 → 0.1.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/README.md +4 -4
- package/package.json +8 -19
- package/src/components/card/Card.tsx +41 -0
- package/src/components/card/index.ts +1 -0
- package/src/components/chat/ChatAttachmentMessageBubble.tsx +246 -0
- package/src/components/chat/ChatConversationRow.tsx +21 -16
- package/src/components/chat/ChatDateDivider.tsx +2 -2
- package/src/components/chat/ChatMessageBubble.tsx +62 -52
- package/src/components/chat/ChatMessageComposer.tsx +16 -14
- package/src/components/chat/ChatQuickReplyChip.tsx +41 -43
- package/src/components/chat/ChatSystemLine.tsx +14 -7
- package/src/components/chat/ChatThreadHeader.tsx +60 -6
- package/src/components/chat/index.ts +1 -2
- package/src/components/index.ts +3 -1
- package/src/components/layout/Divider.tsx +60 -0
- package/src/components/layout/index.ts +1 -0
- package/src/components/list/ListActionItem.tsx +99 -0
- package/src/components/list/ListItem.tsx +96 -0
- package/src/components/list/ListNavigationItem.tsx +102 -0
- package/src/components/list/index.ts +3 -0
- package/src/components/user-interaction/Button.tsx +80 -31
- package/src/components/user-interaction/Checkbox.tsx +72 -32
- package/src/components/user-interaction/IconButton.tsx +68 -30
- package/src/components/user-interaction/Input.tsx +61 -14
- package/src/components/user-interaction/MultiSelect.tsx +142 -75
- package/src/components/user-interaction/SearchBar.tsx +222 -0
- package/src/components/user-interaction/Select.tsx +129 -58
- package/src/components/user-interaction/Switch.tsx +110 -80
- package/src/components/user-interaction/ThemedPressable.tsx +136 -0
- package/src/components/user-interaction/index.ts +2 -0
- package/src/components/visualization-and-display/Avatar.tsx +112 -93
- package/src/components/visualization-and-display/Chip.tsx +22 -22
- package/src/components/visualization-and-display/ThemedIcon.tsx +72 -0
- package/src/components/visualization-and-display/ThemedText.tsx +38 -0
- package/src/components/visualization-and-display/index.ts +2 -1
- package/src/global-contexts/HightideProvider.tsx +19 -10
- package/src/global-contexts/content-theme/ContentThemeContext.ts +22 -0
- package/src/global-contexts/content-theme/ContentThemeProvider.tsx +32 -0
- package/src/global-contexts/content-theme/index.ts +2 -0
- package/src/global-contexts/debug/forward-exports.ts +10 -0
- package/src/global-contexts/debug/index.ts +1 -0
- package/src/global-contexts/index.ts +2 -0
- package/src/global-contexts/theme/ThemeProvider.tsx +7 -1
- package/src/icons/HightideIconRegistry.ts +33 -0
- package/src/icons/index.ts +2 -0
- package/src/icons/types.ts +11 -0
- package/src/theme/adapters/container-adapter.ts +323 -0
- package/src/theme/adapters/defined.ts +11 -0
- package/src/theme/adapters/icon-style-adapter.ts +10 -0
- package/src/theme/adapters/index.ts +4 -0
- package/src/theme/adapters/text-style-adapter.ts +16 -0
- package/src/theme/index.ts +1 -0
- package/src/theme/resolvers/avatar.ts +385 -186
- package/src/theme/resolvers/button.ts +50 -82
- package/src/theme/resolvers/card.ts +27 -0
- package/src/theme/resolvers/chat/attachment-message-bubble.ts +163 -0
- package/src/theme/resolvers/chat/chat-theme.ts +69 -0
- package/src/theme/resolvers/chat/conversation-list.ts +35 -0
- package/src/theme/resolvers/chat/conversation-row.ts +64 -0
- package/src/theme/resolvers/chat/date-divider.ts +31 -0
- package/src/theme/resolvers/chat/index.ts +11 -0
- package/src/theme/resolvers/chat/message-bubble.ts +57 -0
- package/src/theme/resolvers/chat/message-composer.ts +38 -0
- package/src/theme/resolvers/chat/message-list.ts +27 -0
- package/src/theme/resolvers/chat/quick-reply-chip.ts +80 -0
- package/src/theme/resolvers/chat/system-line.ts +41 -0
- package/src/theme/resolvers/chat/thread-header.ts +85 -0
- package/src/theme/resolvers/checkbox.ts +87 -74
- package/src/theme/resolvers/chip.ts +30 -67
- package/src/theme/resolvers/colorScheme.ts +136 -0
- package/src/theme/resolvers/divider.ts +34 -0
- package/src/theme/resolvers/icon.ts +21 -0
- package/src/theme/resolvers/iconButton.ts +45 -61
- package/src/theme/resolvers/index.ts +7 -2
- package/src/theme/resolvers/input.ts +64 -42
- package/src/theme/resolvers/listItem.ts +115 -0
- package/src/theme/resolvers/multiSelect.ts +159 -84
- package/src/theme/resolvers/searchBar.ts +121 -0
- package/src/theme/resolvers/select.ts +141 -66
- package/src/theme/resolvers/switch.ts +59 -53
- package/src/theme/resolvers/themedPressable.ts +54 -0
- package/src/theme/themes/createHightideTheme.ts +214 -51
- package/src/theme/themes/hightideThemes.ts +10 -6
- package/src/theme/types/color.ts +2 -59
- package/src/theme/types/components/avatar.ts +37 -36
- package/src/theme/types/components/button.ts +13 -14
- package/src/theme/types/components/card.ts +9 -0
- package/src/theme/types/components/chat.ts +124 -103
- package/src/theme/types/components/checkbox.ts +11 -12
- package/src/theme/types/components/chip.ts +8 -14
- package/src/theme/types/components/divider.ts +18 -0
- package/src/theme/types/components/hightide.ts +41 -42
- package/src/theme/types/components/iconButton.ts +19 -14
- package/src/theme/types/components/index.ts +5 -1
- package/src/theme/types/components/input.ts +17 -8
- package/src/theme/types/components/listItem.ts +86 -0
- package/src/theme/types/components/multiSelect.ts +14 -12
- package/src/theme/types/components/searchBar.ts +28 -0
- package/src/theme/types/components/select.ts +21 -9
- package/src/theme/types/components/switch.ts +12 -5
- package/src/theme/types/components/themedPressable.ts +31 -0
- package/src/theme/types/decoration.ts +1 -11
- package/src/theme/types/icongraphy.ts +8 -0
- package/src/theme/types/index.ts +2 -0
- package/src/theme/types/layout.ts +25 -57
- package/src/theme/types/resolver.ts +54 -1
- package/src/theme/types/semantics.ts +72 -0
- package/src/theme/types/theme.ts +26 -13
- package/src/theme/types/typography.ts +16 -17
- package/src/utils/hitBoxOverlay.ts +44 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/minimumTouchTargetHitSlop.ts +68 -0
- package/src/components/chat/ChatAttachmentCard.tsx +0 -110
- package/src/components/chat/ChatMessageCard.tsx +0 -118
- package/src/components/menu/Menu.tsx +0 -61
- package/src/components/menu/MenuActionItem.tsx +0 -90
- package/src/components/menu/MenuItem.tsx +0 -73
- package/src/components/menu/MenuNavigationItem.tsx +0 -90
- package/src/components/menu/index.ts +0 -4
- package/src/components/visualization-and-display/Icon.tsx +0 -27
- package/src/storybook/helper.tsx +0 -36
- package/src/theme/resolvers/chat.ts +0 -418
- package/src/theme/resolvers/coloring.ts +0 -94
- package/src/theme/resolvers/menu.ts +0 -120
- package/src/theme/types/components/menu.ts +0 -57
|
@@ -2,39 +2,43 @@ import {
|
|
|
2
2
|
useEffect,
|
|
3
3
|
useMemo,
|
|
4
4
|
useState,
|
|
5
|
-
type ComponentType
|
|
6
|
-
type ReactNode
|
|
5
|
+
type ComponentType
|
|
7
6
|
} from 'react'
|
|
8
7
|
import {
|
|
9
8
|
Image,
|
|
10
|
-
Text,
|
|
11
9
|
View,
|
|
12
10
|
type ImageProps,
|
|
13
11
|
type StyleProp,
|
|
14
12
|
type ViewProps,
|
|
15
13
|
type ViewStyle
|
|
16
14
|
} from 'react-native'
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
import
|
|
15
|
+
import { HightideIconRegistry } from '../../icons/HightideIconRegistry'
|
|
16
|
+
import { ThemedIcon } from './ThemedIcon'
|
|
17
|
+
import { ThemedText } from './ThemedText'
|
|
18
|
+
import {
|
|
19
|
+
avatarSizes,
|
|
20
|
+
type AvatarSize as AvatarSizeToken
|
|
21
|
+
} from '@helpwave/hightide-design/component-token-resolvers'
|
|
22
|
+
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
20
23
|
|
|
21
24
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
22
25
|
import type {
|
|
23
|
-
|
|
26
|
+
AvatarGroupContainerStyle,
|
|
24
27
|
AvatarGroupStackStyle,
|
|
28
|
+
AvatarGroupTextStyle,
|
|
25
29
|
AvatarImageStyle,
|
|
26
30
|
AvatarIconStyle,
|
|
31
|
+
AvatarState,
|
|
27
32
|
AvatarStatus,
|
|
28
33
|
AvatarStyle,
|
|
29
34
|
AvatarTextStyle,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
AvatarWithStatusContainerStyle,
|
|
33
|
-
AvatarStatusDotStyle
|
|
35
|
+
AvatarStatusDotStyle,
|
|
36
|
+
AvatarWithStatusState
|
|
34
37
|
} from '../../theme/types/components/avatar'
|
|
38
|
+
import { avatarStatuses } from '../../theme/types/components/avatar'
|
|
35
39
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
36
40
|
|
|
37
|
-
export type AvatarSize =
|
|
41
|
+
export type AvatarSize = AvatarSizeToken | number
|
|
38
42
|
|
|
39
43
|
type ImageConfig = {
|
|
40
44
|
avatarUrl: string,
|
|
@@ -54,20 +58,21 @@ const DefaultAvatarImage: ComponentType<AvatarImageProps> = ({ alt, ...props })
|
|
|
54
58
|
)
|
|
55
59
|
|
|
56
60
|
export const AvatarUtil = {
|
|
57
|
-
sizes:
|
|
58
|
-
statuses:
|
|
61
|
+
sizes: avatarSizes,
|
|
62
|
+
statuses: avatarStatuses,
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
export type AvatarProps = Omit<ViewProps, 'children' | 'style'> & {
|
|
62
66
|
image?: ImageConfig,
|
|
63
67
|
name?: string,
|
|
64
68
|
size?: AvatarSize,
|
|
69
|
+
color?: ColorPairToken,
|
|
65
70
|
ImageComponent?: ComponentType<AvatarImageProps>,
|
|
66
71
|
style?: StyleProp<ViewStyle>,
|
|
67
|
-
avatarStyle?: StyleOverwrite<
|
|
68
|
-
imageStyle?: StyleOverwrite<
|
|
69
|
-
textStyle?: StyleOverwrite<
|
|
70
|
-
iconStyle?: StyleOverwrite<
|
|
72
|
+
avatarStyle?: StyleOverwrite<AvatarState, AvatarStyle>,
|
|
73
|
+
imageStyle?: StyleOverwrite<AvatarState, AvatarImageStyle>,
|
|
74
|
+
textStyle?: StyleOverwrite<AvatarState, AvatarTextStyle>,
|
|
75
|
+
iconStyle?: StyleOverwrite<AvatarState, AvatarIconStyle>,
|
|
71
76
|
isGrouped?: boolean,
|
|
72
77
|
groupIndex?: number,
|
|
73
78
|
}
|
|
@@ -76,6 +81,7 @@ export const Avatar = ({
|
|
|
76
81
|
image: initialImage,
|
|
77
82
|
name,
|
|
78
83
|
size = 'md',
|
|
84
|
+
color,
|
|
79
85
|
ImageComponent = DefaultAvatarImage,
|
|
80
86
|
style,
|
|
81
87
|
avatarStyle,
|
|
@@ -92,11 +98,12 @@ export const Avatar = ({
|
|
|
92
98
|
const [image, setImage] = useState(initialImage)
|
|
93
99
|
const ImageElement = ImageComponent
|
|
94
100
|
|
|
95
|
-
const state = useMemo(() => ({
|
|
101
|
+
const state = useMemo((): AvatarState => ({
|
|
96
102
|
size,
|
|
97
103
|
isGrouped,
|
|
98
104
|
groupIndex,
|
|
99
|
-
|
|
105
|
+
color,
|
|
106
|
+
}), [size, isGrouped, groupIndex, color])
|
|
100
107
|
|
|
101
108
|
const displayName = useMemo(() => {
|
|
102
109
|
const maxLetters = size === 'sm' ? 1 : 2
|
|
@@ -119,7 +126,7 @@ export const Avatar = ({
|
|
|
119
126
|
setImage(initialImage)
|
|
120
127
|
}, [image?.avatarUrl, initialImage])
|
|
121
128
|
|
|
122
|
-
const resolvedAvatar = theme.components.avatar.
|
|
129
|
+
const resolvedAvatar = theme.components.avatar.container(state, avatarStyle)
|
|
123
130
|
const resolvedImage = theme.components.avatar.image(state, imageStyle)
|
|
124
131
|
const resolvedText = theme.components.avatar.text(state, textStyle)
|
|
125
132
|
const resolvedIcon = theme.components.avatar.icon(state, iconStyle)
|
|
@@ -141,11 +148,11 @@ export const Avatar = ({
|
|
|
141
148
|
)}
|
|
142
149
|
{isShowingFallback && (
|
|
143
150
|
name ? (
|
|
144
|
-
<
|
|
151
|
+
<ThemedText style={resolvedText}>{displayName}</ThemedText>
|
|
145
152
|
) : (
|
|
146
|
-
<
|
|
153
|
+
<ThemedIcon
|
|
154
|
+
icon={HightideIconRegistry.User}
|
|
147
155
|
size={resolvedIcon.size}
|
|
148
|
-
strokeWidth={resolvedIcon.strokeWidth}
|
|
149
156
|
color={resolvedIcon.color}
|
|
150
157
|
/>
|
|
151
158
|
)
|
|
@@ -158,57 +165,91 @@ export type AvatarGroupProps = Omit<ViewProps, 'children' | 'style'> & {
|
|
|
158
165
|
avatars: Omit<AvatarProps, 'size' | 'isGrouped' | 'groupIndex'>[],
|
|
159
166
|
showTotalNumber?: boolean,
|
|
160
167
|
size?: AvatarSize,
|
|
168
|
+
color?: ColorPairToken,
|
|
161
169
|
ImageComponent?: ComponentType<AvatarImageProps>,
|
|
162
170
|
style?: StyleProp<ViewStyle>,
|
|
163
|
-
|
|
164
|
-
|
|
171
|
+
containerStyle?: StyleOverwrite<{ size?: AvatarSize, count?: number }, AvatarGroupContainerStyle>,
|
|
172
|
+
avatarStackStyle?: StyleOverwrite<{ size?: AvatarSize, count?: number }, AvatarGroupStackStyle>,
|
|
173
|
+
textStyle?: StyleOverwrite<{ size?: AvatarSize, count?: number }, AvatarGroupTextStyle>,
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
export const AvatarGroup = ({
|
|
168
177
|
avatars,
|
|
169
178
|
showTotalNumber = true,
|
|
170
179
|
size = 'md',
|
|
180
|
+
color,
|
|
171
181
|
ImageComponent,
|
|
172
182
|
style,
|
|
173
|
-
|
|
174
|
-
|
|
183
|
+
containerStyle,
|
|
184
|
+
avatarStackStyle,
|
|
185
|
+
textStyle,
|
|
175
186
|
...props
|
|
176
187
|
}: AvatarGroupProps) => {
|
|
177
188
|
const { theme } = useTheme()
|
|
178
|
-
const maxShownProfiles =
|
|
189
|
+
const maxShownProfiles = 5
|
|
179
190
|
const displayedProfiles = avatars.length < maxShownProfiles ? avatars : avatars.slice(0, maxShownProfiles)
|
|
180
191
|
const notDisplayedProfiles = avatars.length - maxShownProfiles
|
|
181
192
|
|
|
182
193
|
const state = useMemo(() => ({
|
|
183
194
|
size,
|
|
195
|
+
color,
|
|
184
196
|
count: displayedProfiles.length,
|
|
185
|
-
}), [size, displayedProfiles.length])
|
|
197
|
+
}), [size, color, displayedProfiles.length])
|
|
186
198
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
199
|
+
const avatarResolvers = useMemo(
|
|
200
|
+
() => theme.components.avatarGroup.avatar(state),
|
|
201
|
+
[theme, state]
|
|
202
|
+
)
|
|
203
|
+
const resolvedContainer = theme.components.avatarGroup.container(state, containerStyle)
|
|
204
|
+
const resolvedAvatarStack = theme.components.avatarGroup.avatarStack(state, avatarStackStyle)
|
|
205
|
+
const resolvedText = theme.components.avatarGroup.text(state, textStyle)
|
|
190
206
|
|
|
191
207
|
return (
|
|
192
208
|
<View
|
|
193
209
|
{...props}
|
|
194
210
|
style={[resolvedContainer, style]}
|
|
195
211
|
>
|
|
196
|
-
<View style={
|
|
197
|
-
{displayedProfiles.map((avatar, index) =>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
212
|
+
<View style={resolvedAvatarStack}>
|
|
213
|
+
{displayedProfiles.map((avatar, index) => {
|
|
214
|
+
const avatarState: AvatarState = {
|
|
215
|
+
size,
|
|
216
|
+
isGrouped: true,
|
|
217
|
+
groupIndex: index,
|
|
218
|
+
color: avatar.color ?? color,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<Avatar
|
|
223
|
+
{...avatar}
|
|
224
|
+
key={index}
|
|
225
|
+
size={size}
|
|
226
|
+
isGrouped
|
|
227
|
+
groupIndex={index}
|
|
228
|
+
ImageComponent={avatar.ImageComponent ?? ImageComponent}
|
|
229
|
+
avatarStyle={(_, state) => avatarResolvers.container({
|
|
230
|
+
...state,
|
|
231
|
+
...avatarState,
|
|
232
|
+
})}
|
|
233
|
+
imageStyle={(_, state) => avatarResolvers.image({
|
|
234
|
+
...state,
|
|
235
|
+
...avatarState,
|
|
236
|
+
})}
|
|
237
|
+
textStyle={(_, state) => avatarResolvers.text({
|
|
238
|
+
...state,
|
|
239
|
+
...avatarState,
|
|
240
|
+
})}
|
|
241
|
+
iconStyle={(_, state) => avatarResolvers.icon({
|
|
242
|
+
...state,
|
|
243
|
+
...avatarState,
|
|
244
|
+
})}
|
|
245
|
+
/>
|
|
246
|
+
)
|
|
247
|
+
})}
|
|
207
248
|
</View>
|
|
208
249
|
{showTotalNumber && notDisplayedProfiles > 0 && (
|
|
209
|
-
<
|
|
210
|
-
{
|
|
211
|
-
</
|
|
250
|
+
<ThemedText style={resolvedText}>
|
|
251
|
+
{`+${notDisplayedProfiles}`}
|
|
252
|
+
</ThemedText>
|
|
212
253
|
)}
|
|
213
254
|
</View>
|
|
214
255
|
)
|
|
@@ -218,69 +259,47 @@ export type { AvatarStatus }
|
|
|
218
259
|
|
|
219
260
|
export type AvatarWithStatusProps = AvatarProps & {
|
|
220
261
|
status?: AvatarStatus,
|
|
221
|
-
|
|
222
|
-
statusDotStyle?: StyleOverwrite<{ size?: ElementSize, status?: AvatarStatus }, AvatarStatusDotStyle>,
|
|
262
|
+
statusDotStyle?: StyleOverwrite<AvatarWithStatusState, AvatarStatusDotStyle>,
|
|
223
263
|
}
|
|
224
264
|
|
|
225
265
|
export const AvatarWithStatus = ({
|
|
226
266
|
status = 'unknown',
|
|
227
267
|
size = 'md',
|
|
268
|
+
color,
|
|
228
269
|
style,
|
|
229
|
-
|
|
270
|
+
avatarStyle,
|
|
271
|
+
imageStyle,
|
|
272
|
+
textStyle,
|
|
273
|
+
iconStyle,
|
|
230
274
|
statusDotStyle,
|
|
231
275
|
...avatarProps
|
|
232
276
|
}: AvatarWithStatusProps) => {
|
|
233
277
|
const { theme } = useTheme()
|
|
234
278
|
|
|
235
|
-
const state = useMemo(() => ({
|
|
279
|
+
const state = useMemo((): AvatarWithStatusState => ({
|
|
236
280
|
size,
|
|
281
|
+
color,
|
|
237
282
|
status,
|
|
238
|
-
}), [size, status])
|
|
239
|
-
|
|
240
|
-
const resolvedContainer = theme.components.avatar.withStatus.container(state, containerStyle)
|
|
241
|
-
const resolvedStatusDot = theme.components.avatar.withStatus.statusDot(state, statusDotStyle)
|
|
283
|
+
}), [size, color, status])
|
|
242
284
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
<View style={resolvedStatusDot} />
|
|
247
|
-
</View>
|
|
285
|
+
const avatarResolvers = useMemo(
|
|
286
|
+
() => theme.components.avatarWithStatus.avatar(state),
|
|
287
|
+
[theme, state]
|
|
248
288
|
)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
type AvatarWithLabelPosition = 'left' | 'right'
|
|
252
|
-
|
|
253
|
-
export type AvatarWithLabelProps = AvatarProps & {
|
|
254
|
-
label: ReactNode,
|
|
255
|
-
labelPosition?: AvatarWithLabelPosition,
|
|
256
|
-
containerStyle?: StyleOverwrite<{ size?: ElementSize }, AvatarWithLabelContainerStyle>,
|
|
257
|
-
labelStyle?: StyleOverwrite<{ size?: ElementSize }, AvatarWithLabelTextStyle>,
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export const AvatarWithLabel = ({
|
|
261
|
-
label,
|
|
262
|
-
labelPosition = 'left',
|
|
263
|
-
size = 'md',
|
|
264
|
-
style,
|
|
265
|
-
containerStyle,
|
|
266
|
-
labelStyle,
|
|
267
|
-
...avatarProps
|
|
268
|
-
}: AvatarWithLabelProps) => {
|
|
269
|
-
const { theme } = useTheme()
|
|
270
|
-
|
|
271
|
-
const state = useMemo(() => ({ size }), [size])
|
|
272
|
-
const resolvedContainer = theme.components.avatar.withLabel.container(state, containerStyle)
|
|
273
|
-
const resolvedLabel = theme.components.avatar.withLabel.text(state, labelStyle)
|
|
274
|
-
|
|
275
|
-
const avatar = <Avatar {...avatarProps} size={size} />
|
|
276
|
-
const labelElement = typeof label === 'string' || typeof label === 'number'
|
|
277
|
-
? <Text style={resolvedLabel}>{label}</Text>
|
|
278
|
-
: label
|
|
289
|
+
const resolvedStatusDot = theme.components.avatarWithStatus.statusDot(state, statusDotStyle)
|
|
279
290
|
|
|
280
291
|
return (
|
|
281
|
-
<View style={[
|
|
282
|
-
|
|
283
|
-
|
|
292
|
+
<View style={[{ position: 'relative' }, style]}>
|
|
293
|
+
<Avatar
|
|
294
|
+
{...avatarProps}
|
|
295
|
+
size={size}
|
|
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)}
|
|
301
|
+
/>
|
|
302
|
+
<View style={resolvedStatusDot} />
|
|
284
303
|
</View>
|
|
285
304
|
)
|
|
286
305
|
}
|
|
@@ -3,22 +3,16 @@ import {
|
|
|
3
3
|
type ReactNode
|
|
4
4
|
} from 'react'
|
|
5
5
|
import {
|
|
6
|
-
Text,
|
|
7
6
|
View,
|
|
8
7
|
type StyleProp,
|
|
9
8
|
type ViewProps,
|
|
10
9
|
type ViewStyle
|
|
11
10
|
} from 'react-native'
|
|
12
11
|
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
type ColoringType
|
|
16
|
-
} from '@helpwave/hightide-design/utils'
|
|
17
|
-
import type {
|
|
18
|
-
ChipColoringStyle,
|
|
19
|
-
ElementSize
|
|
20
|
-
} from '@helpwave/hightide-design/types'
|
|
12
|
+
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
13
|
+
import type { ChipVariant, ComponentSize } from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
21
14
|
|
|
15
|
+
import { ContentThemeProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
|
|
22
16
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
23
17
|
import type {
|
|
24
18
|
ChipState,
|
|
@@ -26,20 +20,21 @@ import type {
|
|
|
26
20
|
ChipTextStyle
|
|
27
21
|
} from '../../theme/types/components/chip'
|
|
28
22
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
23
|
+
import type { Color } from '../../theme/types/color'
|
|
24
|
+
import { ThemedText } from './ThemedText'
|
|
29
25
|
|
|
30
|
-
export type ChipSize =
|
|
26
|
+
export type ChipSize = ComponentSize
|
|
31
27
|
|
|
32
|
-
export type ChipColor =
|
|
28
|
+
export type ChipColor = ColorPairToken
|
|
33
29
|
|
|
34
30
|
export const ChipUtil = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
coloringStyles: ['solid', 'tonal', 'outline', 'tonal-outline'] as const satisfies readonly ChipColoringStyle[],
|
|
31
|
+
sizes: ['sm', 'md', 'lg'] as const satisfies readonly ComponentSize[],
|
|
32
|
+
variants: ['filled', 'tonal'] as const satisfies readonly ChipVariant[],
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
export type ChipProps = Omit<ViewProps, 'children' | 'style'> & {
|
|
41
36
|
color?: ChipColor,
|
|
42
|
-
|
|
37
|
+
variant?: ChipVariant,
|
|
43
38
|
size?: ChipSize,
|
|
44
39
|
children?: ReactNode,
|
|
45
40
|
style?: StyleProp<ViewStyle>,
|
|
@@ -49,8 +44,8 @@ export type ChipProps = Omit<ViewProps, 'children' | 'style'> & {
|
|
|
49
44
|
|
|
50
45
|
export const Chip = ({
|
|
51
46
|
children,
|
|
52
|
-
color
|
|
53
|
-
|
|
47
|
+
color,
|
|
48
|
+
variant = 'filled',
|
|
54
49
|
size = 'md',
|
|
55
50
|
style,
|
|
56
51
|
chipStyle,
|
|
@@ -62,8 +57,8 @@ export const Chip = ({
|
|
|
62
57
|
const state = useMemo((): ChipState => ({
|
|
63
58
|
size,
|
|
64
59
|
color,
|
|
65
|
-
|
|
66
|
-
}), [size, color,
|
|
60
|
+
variant,
|
|
61
|
+
}), [size, color, variant])
|
|
67
62
|
|
|
68
63
|
const resolvedChipStyle = useMemo(
|
|
69
64
|
() => theme.components.chip.chip(state, chipStyle),
|
|
@@ -79,9 +74,14 @@ export const Chip = ({
|
|
|
79
74
|
{...props}
|
|
80
75
|
style={[resolvedChipStyle, style]}
|
|
81
76
|
>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
<ContentThemeProvider
|
|
78
|
+
foregroundColor={resolvedTextStyle.color as Color}
|
|
79
|
+
textStyle={resolvedTextStyle}
|
|
80
|
+
>
|
|
81
|
+
{typeof children === 'string' || typeof children === 'number'
|
|
82
|
+
? <ThemedText>{children}</ThemedText>
|
|
83
|
+
: children}
|
|
84
|
+
</ContentThemeProvider>
|
|
85
85
|
</View>
|
|
86
86
|
)
|
|
87
87
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
View,
|
|
3
|
+
type ViewProps
|
|
4
|
+
} from 'react-native'
|
|
5
|
+
|
|
6
|
+
import type { HexColorToken } from '@helpwave/hightide-design/primitive-tokens'
|
|
7
|
+
import type { Appearance } from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
8
|
+
import type { IconSize } from '@helpwave/hightide-design/theme-tokens'
|
|
9
|
+
|
|
10
|
+
import type { IconComponent } from '../../icons/types'
|
|
11
|
+
import { useContentTheme } from '../../global-contexts/content-theme/ContentThemeContext'
|
|
12
|
+
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
13
|
+
|
|
14
|
+
export type ThemedIconAppearance = Appearance
|
|
15
|
+
|
|
16
|
+
export type ThemedIconProps = Omit<ViewProps, 'children'> & {
|
|
17
|
+
icon: IconComponent,
|
|
18
|
+
size?: IconSize | number,
|
|
19
|
+
color?: string,
|
|
20
|
+
strokeWidth?: number,
|
|
21
|
+
appearance?: ThemedIconAppearance,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const ThemedIcon = ({
|
|
25
|
+
icon: Glyph,
|
|
26
|
+
size = 'md',
|
|
27
|
+
color,
|
|
28
|
+
strokeWidth,
|
|
29
|
+
appearance = 'normal',
|
|
30
|
+
style,
|
|
31
|
+
...props
|
|
32
|
+
}: ThemedIconProps) => {
|
|
33
|
+
const { theme } = useTheme()
|
|
34
|
+
const { foregroundColor } = useContentTheme()
|
|
35
|
+
const iconToken = typeof size === 'number'
|
|
36
|
+
? {
|
|
37
|
+
size,
|
|
38
|
+
strokeWidth: strokeWidth ?? theme.components.icon.md.strokeWidth,
|
|
39
|
+
}
|
|
40
|
+
: theme.components.icon[size]
|
|
41
|
+
|
|
42
|
+
const baseColor = (color ?? foregroundColor) as HexColorToken
|
|
43
|
+
const resolvedColor = appearance === 'normal'
|
|
44
|
+
? baseColor
|
|
45
|
+
: theme.semantics.withAppearance({ color: baseColor, appearance })
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<View
|
|
49
|
+
{...props}
|
|
50
|
+
style={[
|
|
51
|
+
{
|
|
52
|
+
width: iconToken.size,
|
|
53
|
+
height: iconToken.size,
|
|
54
|
+
minWidth: iconToken.size,
|
|
55
|
+
maxWidth: iconToken.size,
|
|
56
|
+
minHeight: iconToken.size,
|
|
57
|
+
maxHeight: iconToken.size,
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
justifyContent: 'center',
|
|
60
|
+
overflow: 'hidden',
|
|
61
|
+
},
|
|
62
|
+
style,
|
|
63
|
+
]}
|
|
64
|
+
>
|
|
65
|
+
<Glyph
|
|
66
|
+
size={iconToken.size}
|
|
67
|
+
strokeWidth={strokeWidth ?? iconToken.strokeWidth}
|
|
68
|
+
color={resolvedColor}
|
|
69
|
+
/>
|
|
70
|
+
</View>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef
|
|
3
|
+
} from 'react'
|
|
4
|
+
import {
|
|
5
|
+
Text as RNText,
|
|
6
|
+
type TextProps
|
|
7
|
+
} from 'react-native'
|
|
8
|
+
|
|
9
|
+
import type { HexColorToken } from '@helpwave/hightide-design/primitive-tokens'
|
|
10
|
+
|
|
11
|
+
import { useContentTheme } from '../../global-contexts/content-theme/ContentThemeContext'
|
|
12
|
+
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
13
|
+
|
|
14
|
+
export type ThemedTextAppearance = 'normal' | 'description'
|
|
15
|
+
|
|
16
|
+
export type ThemedTextProps = TextProps & {
|
|
17
|
+
appearance?: ThemedTextAppearance,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ThemedText = forwardRef<React.ComponentRef<typeof RNText>, ThemedTextProps>(function ThemedText({
|
|
21
|
+
appearance = 'normal',
|
|
22
|
+
style,
|
|
23
|
+
...props
|
|
24
|
+
}, ref) {
|
|
25
|
+
const { theme } = useTheme()
|
|
26
|
+
const { foregroundColor, textStyle } = useContentTheme()
|
|
27
|
+
const color = appearance === 'description'
|
|
28
|
+
? theme.semantics.asDescription({ color: foregroundColor as HexColorToken })
|
|
29
|
+
: foregroundColor
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<RNText
|
|
33
|
+
{...props}
|
|
34
|
+
ref={ref}
|
|
35
|
+
style={[textStyle, { color }, style]}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
})
|
|
@@ -8,6 +8,10 @@ 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'
|
|
11
15
|
import {
|
|
12
16
|
LocalizationProvider,
|
|
13
17
|
type LocalizationProviderProps
|
|
@@ -21,11 +25,13 @@ import {
|
|
|
21
25
|
TranslationProvider,
|
|
22
26
|
type TranslationProviderProps
|
|
23
27
|
} from './translation/forward-exports'
|
|
28
|
+
import type { HightideTheme } from '../theme'
|
|
24
29
|
|
|
25
30
|
export type HightideProviderProps = PropsWithChildren & {
|
|
26
|
-
theme?: Omit<ThemeProviderProps
|
|
31
|
+
theme?: Omit<ThemeProviderProps<HightideTheme>, 'children'>,
|
|
27
32
|
locale?: Omit<LocalizationProviderProps, 'children'>,
|
|
28
33
|
translation?: Omit<TranslationProviderProps, 'children' | 'locale'>,
|
|
34
|
+
debug?: Omit<DebugProviderProps, 'children'>,
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
const HightideContextBridge = ({ children }: PropsWithChildren) => {
|
|
@@ -49,6 +55,7 @@ export const HightideProvider = ({
|
|
|
49
55
|
theme,
|
|
50
56
|
locale,
|
|
51
57
|
translation,
|
|
58
|
+
debug,
|
|
52
59
|
}: HightideProviderProps) => {
|
|
53
60
|
const resolvedTranslations = useMemo(() => [
|
|
54
61
|
...ArrayUtil.resolveSingleOrArray(translation?.translation ?? []),
|
|
@@ -56,14 +63,16 @@ export const HightideProvider = ({
|
|
|
56
63
|
], [translation?.translation])
|
|
57
64
|
|
|
58
65
|
return (
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
<DebugProvider {...debug}>
|
|
67
|
+
<LocalizationProvider {...locale}>
|
|
68
|
+
<TranslationProvider {...translation} translation={resolvedTranslations}>
|
|
69
|
+
<ThemeProvider {...theme}>
|
|
70
|
+
<HightideContextBridge>
|
|
71
|
+
{children}
|
|
72
|
+
</HightideContextBridge>
|
|
73
|
+
</ThemeProvider>
|
|
74
|
+
</TranslationProvider>
|
|
75
|
+
</LocalizationProvider>
|
|
76
|
+
</DebugProvider>
|
|
68
77
|
)
|
|
69
78
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext
|
|
4
|
+
} from 'react'
|
|
5
|
+
import type { ColorValue, TextStyle } from 'react-native'
|
|
6
|
+
|
|
7
|
+
export type ContentThemeContextValue = {
|
|
8
|
+
foregroundColor: ColorValue,
|
|
9
|
+
textStyle: TextStyle,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ContentThemeContext = createContext<ContentThemeContextValue | null>(null)
|
|
13
|
+
|
|
14
|
+
export const useContentTheme = (): ContentThemeContextValue => {
|
|
15
|
+
const context = useContext(ContentThemeContext)
|
|
16
|
+
if (!context) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'useContentTheme must be used within ContentThemeProvider. Try adding a ContentThemeProvider around your app.'
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
return context
|
|
22
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useMemo,
|
|
3
|
+
type PropsWithChildren
|
|
4
|
+
} from 'react'
|
|
5
|
+
import type { TextStyle, ColorValue } from 'react-native'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ContentThemeContext,
|
|
9
|
+
type ContentThemeContextValue
|
|
10
|
+
} from './ContentThemeContext'
|
|
11
|
+
|
|
12
|
+
export type ContentThemeProviderProps = PropsWithChildren & {
|
|
13
|
+
foregroundColor: ColorValue,
|
|
14
|
+
textStyle: TextStyle,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const ContentThemeProvider = ({
|
|
18
|
+
children,
|
|
19
|
+
foregroundColor,
|
|
20
|
+
textStyle,
|
|
21
|
+
}: ContentThemeProviderProps) => {
|
|
22
|
+
const value = useMemo((): ContentThemeContextValue => ({
|
|
23
|
+
foregroundColor,
|
|
24
|
+
textStyle,
|
|
25
|
+
}), [foregroundColor, textStyle])
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<ContentThemeContext.Provider value={value}>
|
|
29
|
+
{children}
|
|
30
|
+
</ContentThemeContext.Provider>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './forward-exports'
|