@helpwave/hightide-native 0.6.0 → 0.9.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 +6 -8
- package/src/components/card/Card.tsx +2 -4
- package/src/components/chat/ChatAttachmentMessageBubble.tsx +152 -90
- package/src/components/chat/ChatConversationList.tsx +4 -12
- package/src/components/chat/ChatConversationRow.tsx +159 -164
- package/src/components/chat/ChatDateDivider.tsx +3 -8
- package/src/components/chat/ChatMessageBubble.tsx +52 -45
- package/src/components/chat/ChatMessageComposer.tsx +4 -12
- package/src/components/chat/ChatMessageList.tsx +3 -9
- package/src/components/chat/ChatQuickReplyChip.tsx +41 -27
- package/src/components/chat/ChatSystemLine.tsx +4 -12
- package/src/components/chat/ChatThreadHeader.tsx +136 -101
- package/src/components/layout/Divider.tsx +2 -4
- package/src/components/list/ListActionItem.tsx +57 -65
- package/src/components/list/ListItem.tsx +8 -28
- package/src/components/list/ListItemTextContent.tsx +4 -2
- package/src/components/list/ListNavigationItem.tsx +55 -63
- package/src/components/user-interaction/Button.tsx +43 -49
- package/src/components/user-interaction/Checkbox.tsx +47 -48
- package/src/components/user-interaction/IconButton.tsx +40 -42
- package/src/components/user-interaction/Input.tsx +69 -80
- package/src/components/user-interaction/MultiSelect/MultiSelect.tsx +17 -0
- package/src/components/user-interaction/MultiSelect/MultiSelectComponent.tsx +40 -0
- package/src/components/user-interaction/MultiSelect/MultiSelectContext.tsx +74 -0
- package/src/components/user-interaction/MultiSelect/MultiSelectMenu.tsx +87 -0
- package/src/components/user-interaction/MultiSelect/MultiSelectOption.tsx +106 -0
- package/src/components/user-interaction/MultiSelect/MultiSelectRoot.tsx +194 -0
- package/src/components/user-interaction/MultiSelect/MultiSelectTrigger.tsx +123 -0
- package/src/components/user-interaction/MultiSelect/index.ts +2 -0
- package/src/components/user-interaction/SearchBar.tsx +11 -17
- package/src/components/user-interaction/Select/Select.tsx +17 -0
- package/src/components/user-interaction/Select/SelectComponent.tsx +40 -0
- package/src/components/user-interaction/Select/SelectContext.tsx +73 -0
- package/src/components/user-interaction/Select/SelectMenu.tsx +87 -0
- package/src/components/user-interaction/Select/SelectOption.tsx +96 -0
- package/src/components/user-interaction/Select/SelectRoot.tsx +186 -0
- package/src/components/user-interaction/Select/SelectTrigger.tsx +92 -0
- package/src/components/user-interaction/Select/index.ts +2 -0
- package/src/components/user-interaction/Switch.tsx +46 -98
- package/src/components/user-interaction/Textarea.tsx +165 -12
- package/src/components/user-interaction/ThemedPressable.tsx +48 -49
- package/src/components/visualization-and-display/Avatar.tsx +19 -17
- package/src/components/visualization-and-display/Chip.tsx +4 -12
- package/src/components/visualization-and-display/ThemedText.tsx +12 -5
- package/src/enums/chatMessageDirection.ts +18 -0
- package/src/enums/chatMessageStatus.ts +18 -0
- package/src/enums/hightideThemeModes.ts +18 -0
- package/src/enums/index.ts +7 -0
- package/src/enums/listItemContentOrder.ts +18 -0
- package/src/enums/themedTextAppearance.ts +18 -0
- package/src/enums/useMultiSelectFirstHighlightBehavior.ts +18 -0
- package/src/enums/useSelectFirstHighlightBehavior.ts +18 -0
- package/src/global-contexts/content-theme/ContentThemeProvider.tsx +9 -5
- package/src/global-contexts/theme/ThemeProvider.tsx +4 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useAnimatedStyleTransition.ts +460 -0
- package/src/hooks/useMemoizedTheme.ts +23 -0
- package/src/hooks/useMultiSelect.ts +3 -1
- package/src/hooks/useSelect.ts +3 -1
- package/src/icons/HightideIconRegistry.ts +2 -0
- package/src/theme/adapters/style-adapter-utils.ts +121 -27
- package/src/theme/resolvers/avatar.ts +48 -39
- package/src/theme/resolvers/button.ts +7 -17
- package/src/theme/resolvers/chat/attachment-message-bubble.ts +5 -6
- package/src/theme/resolvers/chat/conversation-row.ts +4 -6
- package/src/theme/resolvers/chat/message-bubble.ts +1 -2
- package/src/theme/resolvers/chat/message-composer.ts +1 -2
- package/src/theme/resolvers/chat/quick-reply-chip.ts +2 -3
- package/src/theme/resolvers/chat/system-line.ts +1 -2
- package/src/theme/resolvers/chat/thread-header.ts +3 -4
- package/src/theme/resolvers/checkbox.ts +2 -2
- package/src/theme/resolvers/chip.ts +1 -2
- package/src/theme/resolvers/iconButton.ts +4 -13
- package/src/theme/resolvers/input.ts +30 -14
- package/src/theme/resolvers/listItem.ts +2 -3
- package/src/theme/resolvers/multiSelect.ts +1 -2
- package/src/theme/resolvers/searchBar.ts +1 -2
- package/src/theme/resolvers/select.ts +1 -2
- package/src/theme/resolvers/themedPressable.ts +4 -15
- package/src/theme/themes/hightideThemes.ts +3 -1
- package/src/theme/types/components/chat.ts +6 -21
- package/src/theme/types/components/input.ts +3 -0
- package/src/theme/types/components/textarea.ts +1 -0
- package/src/theme/types/resolver.ts +4 -27
- package/src/utils/index.ts +1 -0
- package/src/utils/pressableInteraction.ts +7 -0
- package/src/components/user-interaction/MultiSelect.tsx +0 -282
- package/src/components/user-interaction/Select.tsx +0 -242
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useMemo,
|
|
3
|
+
useState,
|
|
3
4
|
type ReactNode
|
|
4
5
|
} from 'react'
|
|
6
|
+
import {
|
|
7
|
+
View,
|
|
8
|
+
type PressableProps
|
|
9
|
+
} from 'react-native'
|
|
5
10
|
|
|
6
11
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
7
|
-
import {
|
|
8
|
-
ThemedPressable,
|
|
9
|
-
type ThemedPressableProps
|
|
10
|
-
} from '../user-interaction/ThemedPressable'
|
|
12
|
+
import { useMemoizedTheme, useMemoizedThemeFactory } from '../../hooks/useMemoizedTheme'
|
|
11
13
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
12
14
|
import type {
|
|
13
15
|
ChatQuickReplyChipState,
|
|
14
16
|
PressableContainerStyle,
|
|
15
17
|
PressableIconStyle,
|
|
16
18
|
PressableState,
|
|
19
|
+
PressableStateLayerStyle,
|
|
17
20
|
PressableTextStyle
|
|
18
21
|
} from '../../theme/types/components/chat'
|
|
19
|
-
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
22
|
+
import type { StyleOverwrite, StyleResolverFunction } from '../../theme/types/resolver'
|
|
23
|
+
import { ThemedPressable } from '../user-interaction'
|
|
20
24
|
|
|
21
|
-
export type ChatQuickReplyChipProps = Omit<
|
|
22
|
-
ThemedPressableProps,
|
|
23
|
-
'children' | 'containerStyle' | 'textStyle' | 'stateLayerStyle' | 'iconStyle'
|
|
24
|
-
> & {
|
|
25
|
+
export type ChatQuickReplyChipProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
25
26
|
isActive?: boolean,
|
|
26
27
|
children?: ReactNode,
|
|
27
28
|
style?: StyleOverwrite<PressableState, PressableContainerStyle>,
|
|
@@ -29,41 +30,54 @@ export type ChatQuickReplyChipProps = Omit<
|
|
|
29
30
|
iconStyle?: StyleOverwrite<PressableState, PressableIconStyle>,
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
type QuickReplyChipPressableResolvers = {
|
|
34
|
+
container: StyleResolverFunction<PressableState, PressableContainerStyle>,
|
|
35
|
+
stateLayer: StyleResolverFunction<PressableState, PressableStateLayerStyle>,
|
|
36
|
+
text: StyleResolverFunction<PressableState, PressableTextStyle>,
|
|
37
|
+
icon: StyleResolverFunction<PressableState, PressableIconStyle>,
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
export const ChatQuickReplyChip = ({
|
|
33
41
|
isActive = false,
|
|
34
42
|
children,
|
|
35
43
|
disabled,
|
|
36
44
|
style,
|
|
37
45
|
textStyle,
|
|
38
|
-
iconStyle,
|
|
39
46
|
...props
|
|
40
47
|
}: ChatQuickReplyChipProps) => {
|
|
41
48
|
const { theme } = useTheme()
|
|
49
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
42
50
|
const state = useMemo((): ChatQuickReplyChipState => ({ isActive }), [isActive])
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
51
|
+
const pressableThemeState = useMemo((): PressableState => ({
|
|
52
|
+
isPressed,
|
|
53
|
+
isDisabled: !!disabled,
|
|
54
|
+
}), [disabled, isPressed])
|
|
55
|
+
const pressableResolvers = useMemoizedThemeFactory<
|
|
56
|
+
ChatQuickReplyChipState,
|
|
57
|
+
QuickReplyChipPressableResolvers
|
|
58
|
+
>(theme.components.chat.quickReplyChip.pressable, state)
|
|
59
|
+
|
|
60
|
+
const resolvedContainerStyle = useMemoizedTheme(pressableResolvers.container, pressableThemeState, style)
|
|
61
|
+
const resolvedStateLayerStyle = useMemoizedTheme(pressableResolvers.stateLayer, pressableThemeState)
|
|
62
|
+
const resolvedTextStyle = useMemoizedTheme(pressableResolvers.text, pressableThemeState, textStyle)
|
|
47
63
|
|
|
48
64
|
return (
|
|
49
65
|
<ThemedPressable
|
|
50
66
|
{...props}
|
|
51
67
|
disabled={disabled}
|
|
52
|
-
style={
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
iconStyle={(pressableState) => (
|
|
62
|
-
pressableResolvers.icon(pressableState, iconStyle)
|
|
63
|
-
)}
|
|
68
|
+
style={resolvedContainerStyle}
|
|
69
|
+
onPressIn={(event) => {
|
|
70
|
+
setIsPressed(true)
|
|
71
|
+
props.onPressIn?.(event)
|
|
72
|
+
}}
|
|
73
|
+
onPressOut={(event) => {
|
|
74
|
+
setIsPressed(false)
|
|
75
|
+
props.onPressOut?.(event)
|
|
76
|
+
}}
|
|
64
77
|
>
|
|
78
|
+
<View pointerEvents="none" style={resolvedStateLayerStyle} />
|
|
65
79
|
{typeof children === 'string' || typeof children === 'number' ? (
|
|
66
|
-
<ThemedText>{children}</ThemedText>
|
|
80
|
+
<ThemedText style={resolvedTextStyle}>{children}</ThemedText>
|
|
67
81
|
) : (
|
|
68
82
|
children
|
|
69
83
|
)}
|
|
@@ -15,6 +15,7 @@ import { HightideIconRegistry } from '../../icons/HightideIconRegistry'
|
|
|
15
15
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
16
16
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
17
17
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
18
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
18
19
|
import type {
|
|
19
20
|
ChatSystemLineState,
|
|
20
21
|
ChatSystemLineStyle,
|
|
@@ -43,18 +44,9 @@ export const ChatSystemLine = ({
|
|
|
43
44
|
const { theme } = useTheme()
|
|
44
45
|
const state = useMemo(() => ({ color }), [color])
|
|
45
46
|
|
|
46
|
-
const resolvedLineStyle =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
50
|
-
const resolvedTextStyle = useMemo(
|
|
51
|
-
() => theme.components.chat.systemLine.text(state, textStyle),
|
|
52
|
-
[theme, state, textStyle]
|
|
53
|
-
)
|
|
54
|
-
const resolvedIcon = useMemo(
|
|
55
|
-
() => theme.components.chat.systemLine.icon(state),
|
|
56
|
-
[theme, state]
|
|
57
|
-
)
|
|
47
|
+
const resolvedLineStyle = useMemoizedTheme(theme.components.chat.systemLine.container, state, lineStyle)
|
|
48
|
+
const resolvedTextStyle = useMemoizedTheme(theme.components.chat.systemLine.text, state, textStyle)
|
|
49
|
+
const resolvedIcon = useMemoizedTheme(theme.components.chat.systemLine.icon, state)
|
|
58
50
|
|
|
59
51
|
return (
|
|
60
52
|
<View {...props} style={[resolvedLineStyle, style]}>
|
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useMemo,
|
|
3
|
+
useState,
|
|
3
4
|
type ReactNode
|
|
4
5
|
} from 'react'
|
|
5
6
|
import {
|
|
7
|
+
StyleSheet,
|
|
6
8
|
View,
|
|
9
|
+
type PressableProps,
|
|
7
10
|
type StyleProp,
|
|
8
11
|
type ViewProps,
|
|
9
12
|
type ViewStyle
|
|
10
13
|
} from 'react-native'
|
|
11
14
|
|
|
12
15
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
16
|
+
import { useMemoizedTheme, useMemoizedThemeFactory } from '../../hooks/useMemoizedTheme'
|
|
13
17
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
14
18
|
import {
|
|
15
19
|
Avatar,
|
|
16
20
|
type AvatarProps
|
|
17
21
|
} from '../visualization-and-display/Avatar'
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} from '
|
|
22
|
+
import type {
|
|
23
|
+
AvatarState,
|
|
24
|
+
AvatarThemeResolvers
|
|
25
|
+
} from '../../theme/types/components/avatar'
|
|
22
26
|
import type {
|
|
23
27
|
ChatThreadHeaderContentRowStyle,
|
|
24
28
|
ChatThreadHeaderStyle,
|
|
@@ -28,6 +32,8 @@ import type {
|
|
|
28
32
|
PressableState
|
|
29
33
|
} from '../../theme/types/components/chat'
|
|
30
34
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
35
|
+
import { ThemedPressable } from '../user-interaction'
|
|
36
|
+
import type { ThemedPressableState, ThemedPressableThemeResolvers } from '../../theme'
|
|
31
37
|
|
|
32
38
|
export type ChatThreadHeaderProps = Omit<ViewProps, 'style'> & {
|
|
33
39
|
avatar?: AvatarProps,
|
|
@@ -35,7 +41,7 @@ export type ChatThreadHeaderProps = Omit<ViewProps, 'style'> & {
|
|
|
35
41
|
subtitle?: ReactNode,
|
|
36
42
|
leftActions?: ReactNode,
|
|
37
43
|
rightActions?: ReactNode,
|
|
38
|
-
onPress?:
|
|
44
|
+
onPress?: PressableProps['onPress'],
|
|
39
45
|
disabled?: boolean,
|
|
40
46
|
style?: StyleProp<ViewStyle>,
|
|
41
47
|
headerStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderStyle>,
|
|
@@ -45,65 +51,146 @@ export type ChatThreadHeaderProps = Omit<ViewProps, 'style'> & {
|
|
|
45
51
|
pressableContainerStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
type ChatThreadHeaderPressableContentProps = {
|
|
55
|
+
avatar?: AvatarProps,
|
|
56
|
+
title: ReactNode,
|
|
57
|
+
subtitle?: ReactNode,
|
|
58
|
+
disabled?: boolean,
|
|
59
|
+
onPress?: PressableProps['onPress'],
|
|
60
|
+
contentRowStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderContentRowStyle>,
|
|
61
|
+
titleStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderTitleStyle>,
|
|
62
|
+
subtitleStyle?: StyleOverwrite<Record<string, never>, ChatThreadHeaderSubtitleStyle>,
|
|
63
|
+
pressableContainerStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const ChatThreadHeaderPressableContent = ({
|
|
49
67
|
avatar,
|
|
50
68
|
title,
|
|
51
69
|
subtitle,
|
|
52
|
-
leftActions,
|
|
53
|
-
rightActions,
|
|
54
|
-
onPress,
|
|
55
70
|
disabled,
|
|
56
|
-
|
|
57
|
-
headerStyle,
|
|
71
|
+
onPress,
|
|
58
72
|
contentRowStyle,
|
|
59
73
|
titleStyle,
|
|
60
74
|
subtitleStyle,
|
|
61
75
|
pressableContainerStyle,
|
|
62
|
-
|
|
63
|
-
}: ChatThreadHeaderProps) => {
|
|
76
|
+
}: ChatThreadHeaderPressableContentProps) => {
|
|
64
77
|
const { theme } = useTheme()
|
|
65
|
-
const
|
|
78
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
79
|
+
const staticState = useMemo(() => ({}), [])
|
|
66
80
|
const resolvedAvatar = useMemo(() => ({
|
|
67
81
|
...avatar,
|
|
68
82
|
}), [avatar])
|
|
69
83
|
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
82
|
-
const
|
|
83
|
-
() => theme.components.chat.threadHeader.subtitle(state, subtitleStyle),
|
|
84
|
-
[theme, state, subtitleStyle]
|
|
85
|
-
)
|
|
86
|
-
const pressableResolvers = useMemo(
|
|
87
|
-
() => theme.components.chat.threadHeader.pressable(state),
|
|
88
|
-
[theme, state]
|
|
89
|
-
)
|
|
84
|
+
const pressableThemeState = useMemo((): PressableState => ({
|
|
85
|
+
isPressed,
|
|
86
|
+
isDisabled: !!disabled,
|
|
87
|
+
}), [disabled, isPressed])
|
|
88
|
+
const pressableResolvers = useMemoizedThemeFactory<
|
|
89
|
+
ThemedPressableState,
|
|
90
|
+
ThemedPressableThemeResolvers
|
|
91
|
+
>(theme.components.chat.threadHeader.pressable, staticState)
|
|
92
|
+
const resolvedContentRowStyle = useMemoizedTheme(theme.components.chat.threadHeader.contentRow, staticState, contentRowStyle)
|
|
93
|
+
const resolvedTitleStyle = useMemoizedTheme(theme.components.chat.threadHeader.title, staticState, titleStyle)
|
|
94
|
+
const resolvedSubtitleStyle = useMemoizedTheme(theme.components.chat.threadHeader.subtitle, staticState, subtitleStyle)
|
|
95
|
+
const resolvedContainerStyle = useMemoizedTheme(pressableResolvers.container, pressableThemeState, pressableContainerStyle)
|
|
96
|
+
const resolvedStateLayerStyle = useMemoizedTheme(pressableResolvers.stateLayer, pressableThemeState)
|
|
90
97
|
|
|
91
|
-
const avatarTheme =
|
|
92
|
-
|
|
98
|
+
const avatarTheme = useMemoizedThemeFactory<AvatarState, AvatarThemeResolvers>(
|
|
99
|
+
theme.components.chat.threadHeader.avatar,
|
|
100
|
+
{
|
|
93
101
|
size: resolvedAvatar.size,
|
|
94
102
|
color: resolvedAvatar.color,
|
|
95
|
-
}
|
|
96
|
-
[theme, resolvedAvatar.size, resolvedAvatar.color]
|
|
103
|
+
}
|
|
97
104
|
)
|
|
98
105
|
const avatarSize = useMemo(() => {
|
|
99
106
|
if (typeof resolvedAvatar.size === 'number' || typeof resolvedAvatar.size === 'string') {
|
|
100
107
|
return resolvedAvatar.size
|
|
101
108
|
}
|
|
102
109
|
|
|
103
|
-
const width = avatarTheme.container({}).width
|
|
110
|
+
const width = StyleSheet.flatten(avatarTheme.container({})).width
|
|
104
111
|
return typeof width === 'number' ? width : resolvedAvatar.size
|
|
105
112
|
}, [avatarTheme, resolvedAvatar.size])
|
|
106
113
|
|
|
114
|
+
return (
|
|
115
|
+
<ThemedPressable
|
|
116
|
+
disabled={disabled}
|
|
117
|
+
onPress={onPress}
|
|
118
|
+
style={resolvedContainerStyle}
|
|
119
|
+
stateLayerStyle={resolvedStateLayerStyle}
|
|
120
|
+
onPressIn={() => setIsPressed(true)}
|
|
121
|
+
onPressOut={() => setIsPressed(false)}
|
|
122
|
+
>
|
|
123
|
+
<Avatar
|
|
124
|
+
{...resolvedAvatar}
|
|
125
|
+
size={avatarSize}
|
|
126
|
+
avatarStyle={(avatarState) => avatarTheme.container(
|
|
127
|
+
{
|
|
128
|
+
...avatarState,
|
|
129
|
+
size: avatarSize,
|
|
130
|
+
},
|
|
131
|
+
resolvedAvatar.avatarStyle
|
|
132
|
+
)}
|
|
133
|
+
imageStyle={(avatarState) => avatarTheme.image(
|
|
134
|
+
{
|
|
135
|
+
...avatarState,
|
|
136
|
+
size: avatarSize,
|
|
137
|
+
},
|
|
138
|
+
resolvedAvatar.imageStyle
|
|
139
|
+
)}
|
|
140
|
+
textStyle={(avatarState) => avatarTheme.text(
|
|
141
|
+
{
|
|
142
|
+
...avatarState,
|
|
143
|
+
size: avatarSize,
|
|
144
|
+
},
|
|
145
|
+
resolvedAvatar.textStyle
|
|
146
|
+
)}
|
|
147
|
+
iconStyle={(avatarState) => avatarTheme.icon(
|
|
148
|
+
{
|
|
149
|
+
...avatarState,
|
|
150
|
+
size: avatarSize,
|
|
151
|
+
},
|
|
152
|
+
resolvedAvatar.iconStyle
|
|
153
|
+
)}
|
|
154
|
+
/>
|
|
155
|
+
<View style={resolvedContentRowStyle}>
|
|
156
|
+
{typeof title === 'string' || typeof title === 'number' ? (
|
|
157
|
+
<ThemedText style={resolvedTitleStyle} numberOfLines={1}>{title}</ThemedText>
|
|
158
|
+
) : (
|
|
159
|
+
title
|
|
160
|
+
)}
|
|
161
|
+
{subtitle != null && (
|
|
162
|
+
typeof subtitle === 'string' || typeof subtitle === 'number' ? (
|
|
163
|
+
<ThemedText style={resolvedSubtitleStyle} numberOfLines={1}>{subtitle}</ThemedText>
|
|
164
|
+
) : (
|
|
165
|
+
subtitle
|
|
166
|
+
)
|
|
167
|
+
)}
|
|
168
|
+
</View>
|
|
169
|
+
</ThemedPressable>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const ChatThreadHeader = ({
|
|
174
|
+
avatar,
|
|
175
|
+
title,
|
|
176
|
+
subtitle,
|
|
177
|
+
leftActions,
|
|
178
|
+
rightActions,
|
|
179
|
+
onPress,
|
|
180
|
+
disabled,
|
|
181
|
+
style,
|
|
182
|
+
headerStyle,
|
|
183
|
+
contentRowStyle,
|
|
184
|
+
titleStyle,
|
|
185
|
+
subtitleStyle,
|
|
186
|
+
pressableContainerStyle,
|
|
187
|
+
...props
|
|
188
|
+
}: ChatThreadHeaderProps) => {
|
|
189
|
+
const { theme } = useTheme()
|
|
190
|
+
const staticState = useMemo(() => ({}), [])
|
|
191
|
+
|
|
192
|
+
const resolvedHeaderStyle = useMemoizedTheme(theme.components.chat.threadHeader.container, staticState, headerStyle)
|
|
193
|
+
|
|
107
194
|
return (
|
|
108
195
|
<View {...props} style={[resolvedHeaderStyle, style]}>
|
|
109
196
|
{leftActions != null && (
|
|
@@ -111,69 +198,17 @@ export const ChatThreadHeader = ({
|
|
|
111
198
|
{leftActions}
|
|
112
199
|
</View>
|
|
113
200
|
)}
|
|
114
|
-
<
|
|
115
|
-
|
|
201
|
+
<ChatThreadHeaderPressableContent
|
|
202
|
+
avatar={avatar}
|
|
203
|
+
title={title}
|
|
204
|
+
subtitle={subtitle}
|
|
116
205
|
disabled={disabled}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
textStyle={(pressableState) => (
|
|
124
|
-
pressableResolvers.text(pressableState)
|
|
125
|
-
)}
|
|
126
|
-
iconStyle={(pressableState) => (
|
|
127
|
-
pressableResolvers.icon(pressableState)
|
|
128
|
-
)}
|
|
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>
|
|
165
|
-
) : (
|
|
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>
|
|
206
|
+
onPress={onPress}
|
|
207
|
+
contentRowStyle={contentRowStyle}
|
|
208
|
+
titleStyle={titleStyle}
|
|
209
|
+
subtitleStyle={subtitleStyle}
|
|
210
|
+
pressableContainerStyle={pressableContainerStyle}
|
|
211
|
+
/>
|
|
177
212
|
{rightActions != null && (
|
|
178
213
|
<View style={{ flexDirection: 'row', alignItems: 'center', flexShrink: 0 }}>
|
|
179
214
|
{rightActions}
|
|
@@ -13,6 +13,7 @@ import type { ColorToken } from '@helpwave/hightide-design/primitive-tokens'
|
|
|
13
13
|
import type { DividerDirection } from '@helpwave/hightide-design/component-token-resolvers'
|
|
14
14
|
|
|
15
15
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
16
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
16
17
|
import type {
|
|
17
18
|
DividerState,
|
|
18
19
|
DividerStyle
|
|
@@ -45,10 +46,7 @@ export const Divider = forwardRef<View, DividerProps>(function Divider({
|
|
|
45
46
|
margin,
|
|
46
47
|
}), [direction, color, width, margin])
|
|
47
48
|
|
|
48
|
-
const resolvedDividerStyle =
|
|
49
|
-
() => theme.components.divider.container(state, dividerStyle),
|
|
50
|
-
[theme, state, dividerStyle]
|
|
51
|
-
)
|
|
49
|
+
const resolvedDividerStyle = useMemoizedTheme(theme.components.divider.container, state, dividerStyle)
|
|
52
50
|
|
|
53
51
|
return (
|
|
54
52
|
<View
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
useMemo,
|
|
3
|
+
useState,
|
|
3
4
|
type ReactNode
|
|
4
5
|
} from 'react'
|
|
5
6
|
import {
|
|
@@ -14,6 +15,7 @@ import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
|
14
15
|
|
|
15
16
|
import { useDebugContext } from '../../global-contexts/debug'
|
|
16
17
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
18
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
17
19
|
import type {
|
|
18
20
|
ListActionItemDescriptionStyle,
|
|
19
21
|
ListActionItemState,
|
|
@@ -43,13 +45,6 @@ export type ListActionItemProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
|
43
45
|
subtitleStyle?: StyleOverwrite<ListActionItemState, ListActionItemDescriptionStyle>,
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
type PressableInteraction = {
|
|
47
|
-
pressed: boolean,
|
|
48
|
-
hovered?: boolean,
|
|
49
|
-
focused?: boolean,
|
|
50
|
-
focusVisible?: boolean,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
48
|
export const ListActionItem = ({
|
|
54
49
|
title,
|
|
55
50
|
subtitle,
|
|
@@ -74,15 +69,21 @@ export const ListActionItem = ({
|
|
|
74
69
|
hitSlop: providedHitSlop,
|
|
75
70
|
onLayout: providedOnLayout,
|
|
76
71
|
})
|
|
72
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
77
73
|
|
|
78
|
-
const
|
|
74
|
+
const resolvedState = useMemo((): ListActionItemState => ({
|
|
79
75
|
color,
|
|
80
76
|
isDisabled: !!disabled,
|
|
81
|
-
isPressed
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
isPressed,
|
|
78
|
+
}), [color, disabled, isPressed])
|
|
79
|
+
|
|
80
|
+
const resolvedItemStyle = useMemoizedTheme(theme.components.listItem.action.container, resolvedState, itemStyle)
|
|
81
|
+
const resolvedLeadingItemContainerStyle = useMemoizedTheme(theme.components.listItem.action.leadingItemContainer, resolvedState)
|
|
82
|
+
const resolvedContentStyle = useMemoizedTheme(theme.components.listItem.action.content, resolvedState)
|
|
83
|
+
const resolvedTrailingItemContainerStyle = useMemoizedTheme(theme.components.listItem.action.trailingItemContainer, resolvedState)
|
|
84
|
+
const resolvedTitleStyle = useMemoizedTheme(theme.components.listItem.action.titleText, resolvedState, titleStyle)
|
|
85
|
+
const resolvedSubtitleStyle = useMemoizedTheme(theme.components.listItem.action.descriptionText, resolvedState, subtitleStyle)
|
|
86
|
+
const resolvedIconStyle = useMemoizedTheme(theme.components.listItem.action.icon, resolvedState)
|
|
86
87
|
|
|
87
88
|
return (
|
|
88
89
|
<Pressable
|
|
@@ -90,59 +91,50 @@ export const ListActionItem = ({
|
|
|
90
91
|
disabled={disabled}
|
|
91
92
|
hitSlop={hitSlop}
|
|
92
93
|
onLayout={onLayout}
|
|
93
|
-
style={
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
style={[resolvedItemStyle, style]}
|
|
95
|
+
onPressIn={(event) => {
|
|
96
|
+
setIsPressed(true)
|
|
97
|
+
props.onPressIn?.(event)
|
|
96
98
|
}}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const resolvedLeadingItemContainerStyle = theme.components.listItem.action.leadingItemContainer(state)
|
|
101
|
-
const resolvedContentStyle = theme.components.listItem.action.content(state)
|
|
102
|
-
const resolvedTrailingItemContainerStyle = theme.components.listItem.action.trailingItemContainer(state)
|
|
103
|
-
const resolvedTitleStyle = theme.components.listItem.action.titleText(state, titleStyle)
|
|
104
|
-
const resolvedSubtitleStyle = theme.components.listItem.action.descriptionText(state, subtitleStyle)
|
|
105
|
-
const resolvedIconStyle = theme.components.listItem.action.icon(state)
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<Fragment>
|
|
109
|
-
{hitBox.isVisualizing && (
|
|
110
|
-
<View
|
|
111
|
-
pointerEvents="none"
|
|
112
|
-
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
113
|
-
/>
|
|
114
|
-
)}
|
|
115
|
-
{leading != null && (
|
|
116
|
-
<ListItemAccessory
|
|
117
|
-
style={resolvedLeadingItemContainerStyle}
|
|
118
|
-
foreground={color?.onColor}
|
|
119
|
-
iconStyle={resolvedIconStyle}
|
|
120
|
-
>
|
|
121
|
-
{leading}
|
|
122
|
-
</ListItemAccessory>
|
|
123
|
-
)}
|
|
124
|
-
<View style={resolvedContentStyle}>
|
|
125
|
-
<ListItemTextContent
|
|
126
|
-
title={title}
|
|
127
|
-
subtitle={subtitle}
|
|
128
|
-
content={content}
|
|
129
|
-
contentOrder={contentOrder}
|
|
130
|
-
titleStyle={resolvedTitleStyle}
|
|
131
|
-
subtitleStyle={resolvedSubtitleStyle}
|
|
132
|
-
/>
|
|
133
|
-
</View>
|
|
134
|
-
{trailing != null && (
|
|
135
|
-
<ListItemAccessory
|
|
136
|
-
style={resolvedTrailingItemContainerStyle}
|
|
137
|
-
foreground={color?.onColor}
|
|
138
|
-
iconStyle={resolvedIconStyle}
|
|
139
|
-
>
|
|
140
|
-
{trailing}
|
|
141
|
-
</ListItemAccessory>
|
|
142
|
-
)}
|
|
143
|
-
</Fragment>
|
|
144
|
-
)
|
|
99
|
+
onPressOut={(event) => {
|
|
100
|
+
setIsPressed(false)
|
|
101
|
+
props.onPressOut?.(event)
|
|
145
102
|
}}
|
|
103
|
+
>
|
|
104
|
+
{hitBox.isVisualizing && (
|
|
105
|
+
<View
|
|
106
|
+
pointerEvents="none"
|
|
107
|
+
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
{leading != null && (
|
|
111
|
+
<ListItemAccessory
|
|
112
|
+
style={resolvedLeadingItemContainerStyle}
|
|
113
|
+
foreground={color?.onColor}
|
|
114
|
+
iconStyle={resolvedIconStyle}
|
|
115
|
+
>
|
|
116
|
+
{leading}
|
|
117
|
+
</ListItemAccessory>
|
|
118
|
+
)}
|
|
119
|
+
<View style={resolvedContentStyle}>
|
|
120
|
+
<ListItemTextContent
|
|
121
|
+
title={title}
|
|
122
|
+
subtitle={subtitle}
|
|
123
|
+
content={content}
|
|
124
|
+
contentOrder={contentOrder}
|
|
125
|
+
titleStyle={resolvedTitleStyle}
|
|
126
|
+
subtitleStyle={resolvedSubtitleStyle}
|
|
127
|
+
/>
|
|
128
|
+
</View>
|
|
129
|
+
{trailing != null && (
|
|
130
|
+
<ListItemAccessory
|
|
131
|
+
style={resolvedTrailingItemContainerStyle}
|
|
132
|
+
foreground={color?.onColor}
|
|
133
|
+
iconStyle={resolvedIconStyle}
|
|
134
|
+
>
|
|
135
|
+
{trailing}
|
|
136
|
+
</ListItemAccessory>
|
|
137
|
+
)}
|
|
146
138
|
</Pressable>
|
|
147
139
|
)
|
|
148
140
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
13
13
|
|
|
14
14
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
15
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
15
16
|
import type {
|
|
16
17
|
ListItemDescriptionStyle,
|
|
17
18
|
ListItemState,
|
|
@@ -58,34 +59,13 @@ export const ListItem = ({
|
|
|
58
59
|
color,
|
|
59
60
|
}), [color])
|
|
60
61
|
|
|
61
|
-
const resolvedItemStyle =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
69
|
-
const resolvedContentStyle = useMemo(
|
|
70
|
-
() => theme.components.listItem.default.content(state),
|
|
71
|
-
[theme, state]
|
|
72
|
-
)
|
|
73
|
-
const resolvedTrailingItemContainerStyle = useMemo(
|
|
74
|
-
() => theme.components.listItem.default.trailingItemContainer(state),
|
|
75
|
-
[theme, state]
|
|
76
|
-
)
|
|
77
|
-
const resolvedTitleStyle = useMemo(
|
|
78
|
-
() => theme.components.listItem.default.titleText(state, titleStyle),
|
|
79
|
-
[theme, state, titleStyle]
|
|
80
|
-
)
|
|
81
|
-
const resolvedSubtitleStyle = useMemo(
|
|
82
|
-
() => theme.components.listItem.default.descriptionText(state, subtitleStyle),
|
|
83
|
-
[theme, state, subtitleStyle]
|
|
84
|
-
)
|
|
85
|
-
const resolvedIconStyle = useMemo(
|
|
86
|
-
() => theme.components.listItem.default.icon(state),
|
|
87
|
-
[theme, state]
|
|
88
|
-
)
|
|
62
|
+
const resolvedItemStyle = useMemoizedTheme(theme.components.listItem.default.container, state, itemStyle)
|
|
63
|
+
const resolvedLeadingItemContainerStyle = useMemoizedTheme(theme.components.listItem.default.leadingItemContainer, state)
|
|
64
|
+
const resolvedContentStyle = useMemoizedTheme(theme.components.listItem.default.content, state)
|
|
65
|
+
const resolvedTrailingItemContainerStyle = useMemoizedTheme(theme.components.listItem.default.trailingItemContainer, state)
|
|
66
|
+
const resolvedTitleStyle = useMemoizedTheme(theme.components.listItem.default.titleText, state, titleStyle)
|
|
67
|
+
const resolvedSubtitleStyle = useMemoizedTheme(theme.components.listItem.default.descriptionText, state, subtitleStyle)
|
|
68
|
+
const resolvedIconStyle = useMemoizedTheme(theme.components.listItem.default.icon, state)
|
|
89
69
|
|
|
90
70
|
return (
|
|
91
71
|
<View {...props} style={[resolvedItemStyle, style]}>
|