@helpwave/hightide-native 0.1.1 → 0.2.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 +2 -2
- package/src/components/chat/ChatAttachmentMessageBubble.tsx +3 -0
- package/src/components/chat/ChatQuickReplyChip.tsx +7 -1
- package/src/components/list/ListActionItem.tsx +60 -11
- package/src/components/list/ListItem.tsx +47 -21
- package/src/components/list/ListItemAccessory.tsx +34 -0
- package/src/components/list/ListItemTextContent.tsx +53 -0
- package/src/components/list/ListNavigationItem.tsx +60 -16
- package/src/components/list/index.ts +2 -0
- package/src/components/user-interaction/Button.tsx +6 -15
- package/src/components/user-interaction/IconButton.tsx +5 -7
- package/src/components/user-interaction/MultiSelect.tsx +6 -8
- package/src/components/user-interaction/Select.tsx +1 -1
- package/src/components/user-interaction/ThemedPressable.tsx +9 -4
- package/src/components/visualization-and-display/Chip.tsx +12 -5
- package/src/components/visualization-and-display/ThemedIcon.tsx +12 -8
- package/src/components/visualization-and-display/ThemedText.tsx +6 -2
- package/src/global-contexts/content-theme/ContentThemeContext.ts +5 -2
- package/src/global-contexts/content-theme/ContentThemeProvider.tsx +64 -10
- package/src/global-contexts/theme/ThemeProvider.tsx +9 -4
- package/src/theme/resolvers/chat/attachment-message-bubble.ts +4 -0
- package/src/theme/resolvers/chat/quick-reply-chip.ts +11 -0
- package/src/theme/resolvers/chip.ts +6 -0
- package/src/theme/resolvers/iconButton.ts +0 -5
- package/src/theme/resolvers/listItem.ts +4 -0
- package/src/theme/resolvers/themedPressable.ts +6 -0
- package/src/theme/types/components/chat.ts +9 -0
- package/src/theme/types/components/chip.ts +4 -0
- package/src/theme/types/components/iconButton.ts +1 -7
- package/src/theme/types/components/listItem.ts +5 -0
- package/src/theme/types/components/themedPressable.ts +4 -0
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.2.0",
|
|
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.2.0",
|
|
47
47
|
"@helpwave/hightide-utils": "0.1.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
@@ -205,6 +205,9 @@ export const ChatAttachmentMessageBubble = ({
|
|
|
205
205
|
textStyle={(_, pressableState) => (
|
|
206
206
|
contentResolvers.text(pressableState)
|
|
207
207
|
)}
|
|
208
|
+
iconStyle={(_, pressableState) => (
|
|
209
|
+
contentResolvers.icon(pressableState)
|
|
210
|
+
)}
|
|
208
211
|
>
|
|
209
212
|
<View style={resolvedFileIconContainerStyle}>
|
|
210
213
|
{icon ?? (
|
|
@@ -13,6 +13,7 @@ import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
|
13
13
|
import type {
|
|
14
14
|
ChatQuickReplyChipState,
|
|
15
15
|
PressableContainerStyle,
|
|
16
|
+
PressableIconStyle,
|
|
16
17
|
PressableState,
|
|
17
18
|
PressableTextStyle
|
|
18
19
|
} from '../../theme/types/components/chat'
|
|
@@ -20,13 +21,14 @@ import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
|
20
21
|
|
|
21
22
|
export type ChatQuickReplyChipProps = Omit<
|
|
22
23
|
ThemedPressableProps,
|
|
23
|
-
'children' | 'containerStyle' | 'textStyle' | 'stateLayerStyle'
|
|
24
|
+
'children' | 'containerStyle' | 'textStyle' | 'stateLayerStyle' | 'iconStyle'
|
|
24
25
|
> & {
|
|
25
26
|
isActive?: boolean,
|
|
26
27
|
children?: ReactNode,
|
|
27
28
|
style?: StyleProp<ViewStyle>,
|
|
28
29
|
containerStyle?: StyleOverwrite<PressableState, PressableContainerStyle>,
|
|
29
30
|
textStyle?: StyleOverwrite<PressableState, PressableTextStyle>,
|
|
31
|
+
iconStyle?: StyleOverwrite<PressableState, PressableIconStyle>,
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export const ChatQuickReplyChip = ({
|
|
@@ -36,6 +38,7 @@ export const ChatQuickReplyChip = ({
|
|
|
36
38
|
style,
|
|
37
39
|
containerStyle,
|
|
38
40
|
textStyle,
|
|
41
|
+
iconStyle,
|
|
39
42
|
...props
|
|
40
43
|
}: ChatQuickReplyChipProps) => {
|
|
41
44
|
const { theme } = useTheme()
|
|
@@ -59,6 +62,9 @@ export const ChatQuickReplyChip = ({
|
|
|
59
62
|
textStyle={(_, pressableState) => (
|
|
60
63
|
pressableResolvers.text(pressableState, textStyle)
|
|
61
64
|
)}
|
|
65
|
+
iconStyle={(_, pressableState) => (
|
|
66
|
+
pressableResolvers.icon(pressableState, iconStyle)
|
|
67
|
+
)}
|
|
62
68
|
>
|
|
63
69
|
{typeof children === 'string' || typeof children === 'number' ? (
|
|
64
70
|
<ThemedText>{children}</ThemedText>
|
|
@@ -12,23 +12,35 @@ import {
|
|
|
12
12
|
|
|
13
13
|
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
14
14
|
|
|
15
|
+
import { useDebugContext } from '../../global-contexts/debug'
|
|
15
16
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
16
|
-
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
17
17
|
import type {
|
|
18
|
+
ListActionItemDescriptionStyle,
|
|
18
19
|
ListActionItemState,
|
|
19
20
|
ListActionItemStyle,
|
|
20
21
|
ListActionItemTitleStyle
|
|
21
22
|
} from '../../theme/types/components/listItem'
|
|
22
23
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
24
|
+
import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
|
|
25
|
+
import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
|
|
26
|
+
import { ListItemAccessory } from './ListItemAccessory'
|
|
27
|
+
import {
|
|
28
|
+
ListItemTextContent,
|
|
29
|
+
type ListItemContentOrder
|
|
30
|
+
} from './ListItemTextContent'
|
|
23
31
|
|
|
24
32
|
export type ListActionItemProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
25
|
-
|
|
33
|
+
title?: string,
|
|
34
|
+
subtitle?: string,
|
|
35
|
+
content?: ReactNode,
|
|
36
|
+
contentOrder?: ListItemContentOrder,
|
|
26
37
|
leading?: ReactNode,
|
|
27
38
|
trailing?: ReactNode,
|
|
28
39
|
color?: ColorPairToken,
|
|
29
40
|
style?: StyleProp<ViewStyle>,
|
|
30
41
|
itemStyle?: StyleOverwrite<ListActionItemState, ListActionItemStyle>,
|
|
31
|
-
|
|
42
|
+
titleStyle?: StyleOverwrite<ListActionItemState, ListActionItemTitleStyle>,
|
|
43
|
+
subtitleStyle?: StyleOverwrite<ListActionItemState, ListActionItemDescriptionStyle>,
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
type PressableInteraction = {
|
|
@@ -39,17 +51,29 @@ type PressableInteraction = {
|
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
export const ListActionItem = ({
|
|
42
|
-
|
|
54
|
+
title,
|
|
55
|
+
subtitle,
|
|
56
|
+
content,
|
|
57
|
+
contentOrder = 'titleFirst',
|
|
43
58
|
leading,
|
|
44
59
|
trailing,
|
|
45
60
|
color,
|
|
46
61
|
disabled,
|
|
47
62
|
style,
|
|
48
63
|
itemStyle,
|
|
49
|
-
|
|
64
|
+
titleStyle,
|
|
65
|
+
subtitleStyle,
|
|
66
|
+
hitSlop: providedHitSlop,
|
|
67
|
+
onLayout: providedOnLayout,
|
|
50
68
|
...props
|
|
51
69
|
}: ListActionItemProps) => {
|
|
52
70
|
const { theme } = useTheme()
|
|
71
|
+
const { hitBox } = useDebugContext()
|
|
72
|
+
const { hitSlop, onLayout } = useMinimumTouchTargetHitSlop({
|
|
73
|
+
touchTargetSize: theme.semantics.touchTargetSize({}),
|
|
74
|
+
hitSlop: providedHitSlop,
|
|
75
|
+
onLayout: providedOnLayout,
|
|
76
|
+
})
|
|
53
77
|
|
|
54
78
|
const resolveState = (interaction: PressableInteraction): ListActionItemState => ({
|
|
55
79
|
color,
|
|
@@ -64,6 +88,8 @@ export const ListActionItem = ({
|
|
|
64
88
|
<Pressable
|
|
65
89
|
{...props}
|
|
66
90
|
disabled={disabled}
|
|
91
|
+
hitSlop={hitSlop}
|
|
92
|
+
onLayout={onLayout}
|
|
67
93
|
style={(pressableState) => {
|
|
68
94
|
const state = resolveState(pressableState as PressableInteraction)
|
|
69
95
|
return [theme.components.listItem.action.container(state, itemStyle), style]
|
|
@@ -74,22 +100,45 @@ export const ListActionItem = ({
|
|
|
74
100
|
const resolvedLeadingItemContainerStyle = theme.components.listItem.action.leadingItemContainer(state)
|
|
75
101
|
const resolvedContentStyle = theme.components.listItem.action.content(state)
|
|
76
102
|
const resolvedTrailingItemContainerStyle = theme.components.listItem.action.trailingItemContainer(state)
|
|
77
|
-
const
|
|
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)
|
|
78
106
|
|
|
79
107
|
return (
|
|
80
108
|
<Fragment>
|
|
109
|
+
{hitBox.isVisualizing && (
|
|
110
|
+
<View
|
|
111
|
+
pointerEvents="none"
|
|
112
|
+
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
81
115
|
{leading != null && (
|
|
82
|
-
<
|
|
116
|
+
<ListItemAccessory
|
|
117
|
+
style={resolvedLeadingItemContainerStyle}
|
|
118
|
+
foreground={color?.onColor}
|
|
119
|
+
iconStyle={resolvedIconStyle}
|
|
120
|
+
>
|
|
83
121
|
{leading}
|
|
84
|
-
</
|
|
122
|
+
</ListItemAccessory>
|
|
85
123
|
)}
|
|
86
124
|
<View style={resolvedContentStyle}>
|
|
87
|
-
<
|
|
125
|
+
<ListItemTextContent
|
|
126
|
+
title={title}
|
|
127
|
+
subtitle={subtitle}
|
|
128
|
+
content={content}
|
|
129
|
+
contentOrder={contentOrder}
|
|
130
|
+
titleStyle={resolvedTitleStyle}
|
|
131
|
+
subtitleStyle={resolvedSubtitleStyle}
|
|
132
|
+
/>
|
|
88
133
|
</View>
|
|
89
134
|
{trailing != null && (
|
|
90
|
-
<
|
|
135
|
+
<ListItemAccessory
|
|
136
|
+
style={resolvedTrailingItemContainerStyle}
|
|
137
|
+
foreground={color?.onColor}
|
|
138
|
+
iconStyle={resolvedIconStyle}
|
|
139
|
+
>
|
|
91
140
|
{trailing}
|
|
92
|
-
</
|
|
141
|
+
</ListItemAccessory>
|
|
93
142
|
)}
|
|
94
143
|
</Fragment>
|
|
95
144
|
)
|
|
@@ -12,7 +12,6 @@ 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 { ThemedText } from '../visualization-and-display/ThemedText'
|
|
16
15
|
import type {
|
|
17
16
|
ListItemDescriptionStyle,
|
|
18
17
|
ListItemState,
|
|
@@ -20,29 +19,38 @@ import type {
|
|
|
20
19
|
ListItemTitleStyle
|
|
21
20
|
} from '../../theme/types/components/listItem'
|
|
22
21
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
22
|
+
import { ListItemAccessory } from './ListItemAccessory'
|
|
23
|
+
import {
|
|
24
|
+
ListItemTextContent,
|
|
25
|
+
type ListItemContentOrder
|
|
26
|
+
} from './ListItemTextContent'
|
|
23
27
|
|
|
24
28
|
export type ListItemProps = Omit<ViewProps, 'style'> & {
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
title?: string,
|
|
30
|
+
subtitle?: string,
|
|
31
|
+
content?: ReactNode,
|
|
32
|
+
contentOrder?: ListItemContentOrder,
|
|
27
33
|
leading?: ReactNode,
|
|
28
34
|
trailing?: ReactNode,
|
|
29
35
|
color?: ColorPairToken,
|
|
30
36
|
style?: StyleProp<ViewStyle>,
|
|
31
37
|
itemStyle?: StyleOverwrite<ListItemState, ListItemStyle>,
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
titleStyle?: StyleOverwrite<ListItemState, ListItemTitleStyle>,
|
|
39
|
+
subtitleStyle?: StyleOverwrite<ListItemState, ListItemDescriptionStyle>,
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
export const ListItem = ({
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
title,
|
|
44
|
+
subtitle,
|
|
45
|
+
content,
|
|
46
|
+
contentOrder = 'subtitleFirst',
|
|
39
47
|
leading,
|
|
40
48
|
trailing,
|
|
41
49
|
color,
|
|
42
50
|
style,
|
|
43
51
|
itemStyle,
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
titleStyle,
|
|
53
|
+
subtitleStyle,
|
|
46
54
|
...props
|
|
47
55
|
}: ListItemProps) => {
|
|
48
56
|
const { theme } = useTheme()
|
|
@@ -66,30 +74,48 @@ export const ListItem = ({
|
|
|
66
74
|
() => theme.components.listItem.default.trailingItemContainer(state),
|
|
67
75
|
[theme, state]
|
|
68
76
|
)
|
|
69
|
-
const
|
|
70
|
-
() => theme.components.listItem.default.
|
|
71
|
-
[theme, state,
|
|
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]
|
|
72
84
|
)
|
|
73
|
-
const
|
|
74
|
-
() => theme.components.listItem.default.
|
|
75
|
-
[theme, state
|
|
85
|
+
const resolvedIconStyle = useMemo(
|
|
86
|
+
() => theme.components.listItem.default.icon(state),
|
|
87
|
+
[theme, state]
|
|
76
88
|
)
|
|
77
89
|
|
|
78
90
|
return (
|
|
79
91
|
<View {...props} style={[resolvedItemStyle, style]}>
|
|
80
92
|
{leading != null && (
|
|
81
|
-
<
|
|
93
|
+
<ListItemAccessory
|
|
94
|
+
style={resolvedLeadingItemContainerStyle}
|
|
95
|
+
foreground={color?.onColor}
|
|
96
|
+
iconStyle={resolvedIconStyle}
|
|
97
|
+
>
|
|
82
98
|
{leading}
|
|
83
|
-
</
|
|
99
|
+
</ListItemAccessory>
|
|
84
100
|
)}
|
|
85
101
|
<View style={resolvedContentStyle}>
|
|
86
|
-
<
|
|
87
|
-
|
|
102
|
+
<ListItemTextContent
|
|
103
|
+
title={title}
|
|
104
|
+
subtitle={subtitle}
|
|
105
|
+
content={content}
|
|
106
|
+
contentOrder={contentOrder}
|
|
107
|
+
titleStyle={resolvedTitleStyle}
|
|
108
|
+
subtitleStyle={resolvedSubtitleStyle}
|
|
109
|
+
/>
|
|
88
110
|
</View>
|
|
89
111
|
{trailing != null && (
|
|
90
|
-
<
|
|
112
|
+
<ListItemAccessory
|
|
113
|
+
style={resolvedTrailingItemContainerStyle}
|
|
114
|
+
foreground={color?.onColor}
|
|
115
|
+
iconStyle={resolvedIconStyle}
|
|
116
|
+
>
|
|
91
117
|
{trailing}
|
|
92
|
-
</
|
|
118
|
+
</ListItemAccessory>
|
|
93
119
|
)}
|
|
94
120
|
</View>
|
|
95
121
|
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
type StyleProp,
|
|
5
|
+
type ViewStyle
|
|
6
|
+
} from 'react-native'
|
|
7
|
+
|
|
8
|
+
import type { HexColorToken } from '@helpwave/hightide-design/primitive-tokens'
|
|
9
|
+
|
|
10
|
+
import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
|
|
11
|
+
import type { IconStyle } from '../../icons'
|
|
12
|
+
|
|
13
|
+
export type ListItemAccessoryProps = {
|
|
14
|
+
children: ReactNode,
|
|
15
|
+
style?: StyleProp<ViewStyle>,
|
|
16
|
+
foreground?: HexColorToken,
|
|
17
|
+
iconStyle: IconStyle,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ListItemAccessory = ({
|
|
21
|
+
children,
|
|
22
|
+
style,
|
|
23
|
+
foreground,
|
|
24
|
+
iconStyle,
|
|
25
|
+
}: ListItemAccessoryProps) => (
|
|
26
|
+
<View style={style}>
|
|
27
|
+
<ContentThemeOverrideProvider
|
|
28
|
+
foreground={foreground}
|
|
29
|
+
iconStyle={iconStyle}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
</ContentThemeOverrideProvider>
|
|
33
|
+
</View>
|
|
34
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import { Fragment } from 'react'
|
|
3
|
+
import type { StyleProp, TextStyle } from 'react-native'
|
|
4
|
+
|
|
5
|
+
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
6
|
+
|
|
7
|
+
export type ListItemContentOrder = 'titleFirst' | 'subtitleFirst'
|
|
8
|
+
|
|
9
|
+
export type ListItemTextContentProps = {
|
|
10
|
+
title?: string,
|
|
11
|
+
subtitle?: string,
|
|
12
|
+
content?: ReactNode,
|
|
13
|
+
contentOrder?: ListItemContentOrder,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ListItemTextContent = ({
|
|
17
|
+
title,
|
|
18
|
+
subtitle,
|
|
19
|
+
content,
|
|
20
|
+
contentOrder = 'titleFirst',
|
|
21
|
+
titleStyle,
|
|
22
|
+
subtitleStyle,
|
|
23
|
+
}: ListItemTextContentProps & {
|
|
24
|
+
titleStyle?: StyleProp<TextStyle>,
|
|
25
|
+
subtitleStyle?: StyleProp<TextStyle>,
|
|
26
|
+
}) => {
|
|
27
|
+
if (content != null) {
|
|
28
|
+
return <>{content}</>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const titleNode = title != null
|
|
32
|
+
? <ThemedText style={titleStyle}>{title}</ThemedText>
|
|
33
|
+
: null
|
|
34
|
+
const subtitleNode = subtitle != null
|
|
35
|
+
? <ThemedText style={subtitleStyle}>{subtitle}</ThemedText>
|
|
36
|
+
: null
|
|
37
|
+
|
|
38
|
+
if (contentOrder === 'subtitleFirst') {
|
|
39
|
+
return (
|
|
40
|
+
<Fragment>
|
|
41
|
+
{subtitleNode}
|
|
42
|
+
{titleNode}
|
|
43
|
+
</Fragment>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Fragment>
|
|
49
|
+
{titleNode}
|
|
50
|
+
{subtitleNode}
|
|
51
|
+
</Fragment>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -14,22 +14,34 @@ import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
|
14
14
|
|
|
15
15
|
import { HightideIconRegistry } from '../../icons/HightideIconRegistry'
|
|
16
16
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
17
|
-
import {
|
|
17
|
+
import { useDebugContext } from '../../global-contexts/debug'
|
|
18
18
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
19
19
|
import type {
|
|
20
|
+
ListNavigationItemDescriptionStyle,
|
|
20
21
|
ListNavigationItemState,
|
|
21
22
|
ListNavigationItemStyle,
|
|
22
23
|
ListNavigationItemTitleStyle
|
|
23
24
|
} from '../../theme/types/components/listItem'
|
|
24
25
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
26
|
+
import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
|
|
27
|
+
import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
|
|
28
|
+
import { ListItemAccessory } from './ListItemAccessory'
|
|
29
|
+
import {
|
|
30
|
+
ListItemTextContent,
|
|
31
|
+
type ListItemContentOrder
|
|
32
|
+
} from './ListItemTextContent'
|
|
25
33
|
|
|
26
34
|
export type ListNavigationItemProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
27
|
-
|
|
35
|
+
title?: string,
|
|
36
|
+
subtitle?: string,
|
|
37
|
+
content?: ReactNode,
|
|
38
|
+
contentOrder?: ListItemContentOrder,
|
|
28
39
|
leading?: ReactNode,
|
|
29
40
|
color?: ColorPairToken,
|
|
30
41
|
style?: StyleProp<ViewStyle>,
|
|
31
42
|
itemStyle?: StyleOverwrite<ListNavigationItemState, ListNavigationItemStyle>,
|
|
32
|
-
|
|
43
|
+
titleStyle?: StyleOverwrite<ListNavigationItemState, ListNavigationItemTitleStyle>,
|
|
44
|
+
subtitleStyle?: StyleOverwrite<ListNavigationItemState, ListNavigationItemDescriptionStyle>,
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
type PressableInteraction = {
|
|
@@ -40,16 +52,28 @@ type PressableInteraction = {
|
|
|
40
52
|
}
|
|
41
53
|
|
|
42
54
|
export const ListNavigationItem = ({
|
|
43
|
-
|
|
55
|
+
title,
|
|
56
|
+
subtitle,
|
|
57
|
+
content,
|
|
58
|
+
contentOrder = 'titleFirst',
|
|
44
59
|
leading,
|
|
45
60
|
color,
|
|
46
61
|
disabled,
|
|
47
62
|
style,
|
|
48
63
|
itemStyle,
|
|
49
|
-
|
|
64
|
+
titleStyle,
|
|
65
|
+
subtitleStyle,
|
|
66
|
+
hitSlop: providedHitSlop,
|
|
67
|
+
onLayout: providedOnLayout,
|
|
50
68
|
...props
|
|
51
69
|
}: ListNavigationItemProps) => {
|
|
52
70
|
const { theme } = useTheme()
|
|
71
|
+
const { hitBox } = useDebugContext()
|
|
72
|
+
const { hitSlop, onLayout } = useMinimumTouchTargetHitSlop({
|
|
73
|
+
touchTargetSize: theme.semantics.touchTargetSize({}),
|
|
74
|
+
hitSlop: providedHitSlop,
|
|
75
|
+
onLayout: providedOnLayout,
|
|
76
|
+
})
|
|
53
77
|
|
|
54
78
|
const resolveState = (interaction: PressableInteraction): ListNavigationItemState => ({
|
|
55
79
|
color,
|
|
@@ -64,6 +88,8 @@ export const ListNavigationItem = ({
|
|
|
64
88
|
<Pressable
|
|
65
89
|
{...props}
|
|
66
90
|
disabled={disabled}
|
|
91
|
+
hitSlop={hitSlop}
|
|
92
|
+
onLayout={onLayout}
|
|
67
93
|
style={(pressableState) => {
|
|
68
94
|
const state = resolveState(pressableState as PressableInteraction)
|
|
69
95
|
return [theme.components.listItem.navigation.container(state, itemStyle), style]
|
|
@@ -74,26 +100,44 @@ export const ListNavigationItem = ({
|
|
|
74
100
|
const resolvedLeadingItemContainerStyle = theme.components.listItem.navigation.leadingItemContainer(state)
|
|
75
101
|
const resolvedContentStyle = theme.components.listItem.navigation.content(state)
|
|
76
102
|
const resolvedTrailingItemContainerStyle = theme.components.listItem.navigation.trailingItemContainer(state)
|
|
77
|
-
const
|
|
78
|
-
const
|
|
103
|
+
const resolvedTitleStyle = theme.components.listItem.navigation.titleText(state, titleStyle)
|
|
104
|
+
const resolvedSubtitleStyle = theme.components.listItem.navigation.descriptionText(state, subtitleStyle)
|
|
105
|
+
const resolvedIconStyle = theme.components.listItem.navigation.icon(state)
|
|
79
106
|
|
|
80
107
|
return (
|
|
81
108
|
<Fragment>
|
|
109
|
+
{hitBox.isVisualizing && (
|
|
110
|
+
<View
|
|
111
|
+
pointerEvents="none"
|
|
112
|
+
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
82
115
|
{leading != null && (
|
|
83
|
-
<
|
|
116
|
+
<ListItemAccessory
|
|
117
|
+
style={resolvedLeadingItemContainerStyle}
|
|
118
|
+
foreground={color?.onColor}
|
|
119
|
+
iconStyle={resolvedIconStyle}
|
|
120
|
+
>
|
|
84
121
|
{leading}
|
|
85
|
-
</
|
|
122
|
+
</ListItemAccessory>
|
|
86
123
|
)}
|
|
87
124
|
<View style={resolvedContentStyle}>
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
125
|
+
<ListItemTextContent
|
|
126
|
+
title={title}
|
|
127
|
+
subtitle={subtitle}
|
|
128
|
+
content={content}
|
|
129
|
+
contentOrder={contentOrder}
|
|
130
|
+
titleStyle={resolvedTitleStyle}
|
|
131
|
+
subtitleStyle={resolvedSubtitleStyle}
|
|
95
132
|
/>
|
|
96
133
|
</View>
|
|
134
|
+
<ListItemAccessory
|
|
135
|
+
style={resolvedTrailingItemContainerStyle}
|
|
136
|
+
foreground={color?.onColor}
|
|
137
|
+
iconStyle={resolvedIconStyle}
|
|
138
|
+
>
|
|
139
|
+
<ThemedIcon icon={HightideIconRegistry.ChevronRight} />
|
|
140
|
+
</ListItemAccessory>
|
|
97
141
|
</Fragment>
|
|
98
142
|
)
|
|
99
143
|
}}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
11
11
|
import type { ComponentSize, ButtonVariant } from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
|
|
14
14
|
import { useDebugContext } from '../../global-contexts/debug'
|
|
15
15
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
16
16
|
import type { IconComponent } from '../../icons/types'
|
|
@@ -20,7 +20,6 @@ import type {
|
|
|
20
20
|
ButtonTextStyle
|
|
21
21
|
} from '../../theme/types/components/button'
|
|
22
22
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
23
|
-
import type { Color } from '../../theme/types/color'
|
|
24
23
|
import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
|
|
25
24
|
import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
|
|
26
25
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
@@ -122,26 +121,18 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
|
|
|
122
121
|
pointerEvents="none"
|
|
123
122
|
style={theme.components.button.stateLayer(state, stateLayerStyle)}
|
|
124
123
|
/>
|
|
125
|
-
<
|
|
126
|
-
foregroundColor={resolvedText.color as Color}
|
|
124
|
+
<ContentThemeOverrideProvider
|
|
127
125
|
textStyle={resolvedText}
|
|
126
|
+
iconStyle={resolvedIcon}
|
|
128
127
|
>
|
|
129
128
|
{leadingIcon !== undefined && (
|
|
130
|
-
<ThemedIcon
|
|
131
|
-
icon={leadingIcon}
|
|
132
|
-
size={resolvedIcon.size}
|
|
133
|
-
strokeWidth={resolvedIcon.strokeWidth}
|
|
134
|
-
/>
|
|
129
|
+
<ThemedIcon icon={leadingIcon} />
|
|
135
130
|
)}
|
|
136
131
|
<ThemedText>{children}</ThemedText>
|
|
137
132
|
{trailingIcon !== undefined && (
|
|
138
|
-
<ThemedIcon
|
|
139
|
-
icon={trailingIcon}
|
|
140
|
-
size={resolvedIcon.size}
|
|
141
|
-
strokeWidth={resolvedIcon.strokeWidth}
|
|
142
|
-
/>
|
|
133
|
+
<ThemedIcon icon={trailingIcon} />
|
|
143
134
|
)}
|
|
144
|
-
</
|
|
135
|
+
</ContentThemeOverrideProvider>
|
|
145
136
|
</Fragment>
|
|
146
137
|
)
|
|
147
138
|
}}
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
IconButtonVariant
|
|
13
13
|
} from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
|
|
16
16
|
import { useDebugContext } from '../../global-contexts/debug'
|
|
17
17
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
18
18
|
import type {
|
|
@@ -105,7 +105,6 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
105
105
|
{(pressableState) => {
|
|
106
106
|
const state = resolveState(pressableState as PressableInteraction)
|
|
107
107
|
const resolvedIcon = theme.components.iconButton.icon(state)
|
|
108
|
-
const resolvedText = theme.components.iconButton.text(state)
|
|
109
108
|
|
|
110
109
|
return (
|
|
111
110
|
<Fragment>
|
|
@@ -119,12 +118,11 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
119
118
|
pointerEvents="none"
|
|
120
119
|
style={theme.components.iconButton.stateLayer(state, stateLayerStyle)}
|
|
121
120
|
/>
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
textStyle={resolvedText}
|
|
121
|
+
<ContentThemeOverrideProvider
|
|
122
|
+
iconStyle={resolvedIcon}
|
|
125
123
|
>
|
|
126
|
-
<ThemedIcon icon={IconComponent}
|
|
127
|
-
</
|
|
124
|
+
<ThemedIcon icon={IconComponent} />
|
|
125
|
+
</ContentThemeOverrideProvider>
|
|
128
126
|
</Fragment>
|
|
129
127
|
)
|
|
130
128
|
}}
|
|
@@ -224,19 +224,17 @@ export const MultiSelect = ({
|
|
|
224
224
|
|
|
225
225
|
return (
|
|
226
226
|
<ListActionItem
|
|
227
|
-
|
|
227
|
+
title={item.label ?? item.id}
|
|
228
228
|
color={optionColor}
|
|
229
229
|
disabled={item.disabled}
|
|
230
230
|
onPress={() => multiSelect.toggleSelection(item.id)}
|
|
231
231
|
leading={(
|
|
232
232
|
<View style={multiSelectTheme.checkbox(optionState)}>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
/>
|
|
239
|
-
)}
|
|
233
|
+
<ThemedIcon
|
|
234
|
+
icon={HightideIconRegistry.Check}
|
|
235
|
+
size="sm"
|
|
236
|
+
color={checkboxIcon.color}
|
|
237
|
+
/>
|
|
240
238
|
</View>
|
|
241
239
|
)}
|
|
242
240
|
/>
|
|
@@ -12,10 +12,11 @@ import type {
|
|
|
12
12
|
} from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
13
13
|
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
|
|
16
16
|
import { useDebugContext } from '../../global-contexts/debug'
|
|
17
17
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
18
18
|
import type {
|
|
19
|
+
ThemedPressableIconStyle,
|
|
19
20
|
ThemedPressableState,
|
|
20
21
|
ThemedPressableStyle,
|
|
21
22
|
ThemedPressableTextStyle
|
|
@@ -40,6 +41,7 @@ export type ThemedPressableProps = PressableProps & {
|
|
|
40
41
|
hasAdditionalHorizontalPadding?: boolean,
|
|
41
42
|
containerStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableStyle>,
|
|
42
43
|
stateLayerStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableStyle>,
|
|
44
|
+
iconStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableIconStyle>,
|
|
43
45
|
textStyle?: StyleOverwrite<ThemedPressableState, ThemedPressableTextStyle>,
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -61,6 +63,7 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
|
|
|
61
63
|
style,
|
|
62
64
|
containerStyle,
|
|
63
65
|
stateLayerStyle,
|
|
66
|
+
iconStyle,
|
|
64
67
|
textStyle,
|
|
65
68
|
hitSlop: providedHitSlop,
|
|
66
69
|
onLayout: providedOnLayout,
|
|
@@ -106,6 +109,7 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
|
|
|
106
109
|
{(pressableState) => {
|
|
107
110
|
const state = resolveState(pressableState as PressableInteraction)
|
|
108
111
|
const resolvedText = theme.components.themedPressable.text(state, textStyle)
|
|
112
|
+
const resolvedIcon = theme.components.themedPressable.icon(state, iconStyle)
|
|
109
113
|
const resolvedChildren = typeof children === 'function'
|
|
110
114
|
? children(pressableState)
|
|
111
115
|
: children
|
|
@@ -122,12 +126,13 @@ export const ThemedPressable = forwardRef<React.ComponentRef<typeof Pressable>,
|
|
|
122
126
|
pointerEvents="none"
|
|
123
127
|
style={theme.components.themedPressable.stateLayer(state, stateLayerStyle)}
|
|
124
128
|
/>
|
|
125
|
-
<
|
|
126
|
-
|
|
129
|
+
<ContentThemeOverrideProvider
|
|
130
|
+
foreground={resolvedText.color}
|
|
127
131
|
textStyle={resolvedText}
|
|
132
|
+
iconStyle={resolvedIcon}
|
|
128
133
|
>
|
|
129
134
|
{resolvedChildren}
|
|
130
|
-
</
|
|
135
|
+
</ContentThemeOverrideProvider>
|
|
131
136
|
</Fragment>
|
|
132
137
|
)
|
|
133
138
|
}}
|
|
@@ -12,15 +12,15 @@ import {
|
|
|
12
12
|
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
13
13
|
import type { ChipVariant, ComponentSize } from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider'
|
|
16
16
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
17
17
|
import type {
|
|
18
|
+
ChipIconStyle,
|
|
18
19
|
ChipState,
|
|
19
20
|
ChipStyle,
|
|
20
21
|
ChipTextStyle
|
|
21
22
|
} from '../../theme/types/components/chip'
|
|
22
23
|
import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
23
|
-
import type { Color } from '../../theme/types/color'
|
|
24
24
|
import { ThemedText } from './ThemedText'
|
|
25
25
|
|
|
26
26
|
export type ChipSize = ComponentSize
|
|
@@ -39,6 +39,7 @@ export type ChipProps = Omit<ViewProps, 'children' | 'style'> & {
|
|
|
39
39
|
children?: ReactNode,
|
|
40
40
|
style?: StyleProp<ViewStyle>,
|
|
41
41
|
chipStyle?: StyleOverwrite<ChipState, ChipStyle>,
|
|
42
|
+
iconStyle?: StyleOverwrite<ChipState, ChipIconStyle>,
|
|
42
43
|
textStyle?: StyleOverwrite<ChipState, ChipTextStyle>,
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -49,6 +50,7 @@ export const Chip = ({
|
|
|
49
50
|
size = 'md',
|
|
50
51
|
style,
|
|
51
52
|
chipStyle,
|
|
53
|
+
iconStyle,
|
|
52
54
|
textStyle,
|
|
53
55
|
...props
|
|
54
56
|
}: ChipProps) => {
|
|
@@ -64,6 +66,10 @@ export const Chip = ({
|
|
|
64
66
|
() => theme.components.chip.chip(state, chipStyle),
|
|
65
67
|
[theme, state, chipStyle]
|
|
66
68
|
)
|
|
69
|
+
const resolvedIconStyle = useMemo(
|
|
70
|
+
() => theme.components.chip.icon(state, iconStyle),
|
|
71
|
+
[theme, state, iconStyle]
|
|
72
|
+
)
|
|
67
73
|
const resolvedTextStyle = useMemo(
|
|
68
74
|
() => theme.components.chip.text(state, textStyle),
|
|
69
75
|
[theme, state, textStyle]
|
|
@@ -74,14 +80,15 @@ export const Chip = ({
|
|
|
74
80
|
{...props}
|
|
75
81
|
style={[resolvedChipStyle, style]}
|
|
76
82
|
>
|
|
77
|
-
<
|
|
78
|
-
|
|
83
|
+
<ContentThemeOverrideProvider
|
|
84
|
+
foreground={resolvedTextStyle.color}
|
|
79
85
|
textStyle={resolvedTextStyle}
|
|
86
|
+
iconStyle={resolvedIconStyle}
|
|
80
87
|
>
|
|
81
88
|
{typeof children === 'string' || typeof children === 'number'
|
|
82
89
|
? <ThemedText>{children}</ThemedText>
|
|
83
90
|
: children}
|
|
84
|
-
</
|
|
91
|
+
</ContentThemeOverrideProvider>
|
|
85
92
|
</View>
|
|
86
93
|
)
|
|
87
94
|
}
|
|
@@ -23,7 +23,7 @@ export type ThemedIconProps = Omit<ViewProps, 'children'> & {
|
|
|
23
23
|
|
|
24
24
|
export const ThemedIcon = ({
|
|
25
25
|
icon: Glyph,
|
|
26
|
-
size
|
|
26
|
+
size,
|
|
27
27
|
color,
|
|
28
28
|
strokeWidth,
|
|
29
29
|
appearance = 'normal',
|
|
@@ -31,15 +31,19 @@ export const ThemedIcon = ({
|
|
|
31
31
|
...props
|
|
32
32
|
}: ThemedIconProps) => {
|
|
33
33
|
const { theme } = useTheme()
|
|
34
|
-
const {
|
|
35
|
-
const
|
|
34
|
+
const { foreground, iconStyle } = useContentTheme()
|
|
35
|
+
const resolvedSize = size ?? iconStyle.size ?? 'md'
|
|
36
|
+
const iconToken = typeof resolvedSize === 'number'
|
|
36
37
|
? {
|
|
37
|
-
size,
|
|
38
|
-
strokeWidth: strokeWidth ?? theme.components.icon.md.strokeWidth,
|
|
38
|
+
size: resolvedSize,
|
|
39
|
+
strokeWidth: strokeWidth ?? iconStyle.strokeWidth ?? theme.components.icon.md.strokeWidth,
|
|
39
40
|
}
|
|
40
|
-
: theme.components.icon[
|
|
41
|
+
: theme.components.icon[resolvedSize]
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
// TODO fix this by using a hex color parser
|
|
44
|
+
const baseColor = (color
|
|
45
|
+
?? iconStyle.color
|
|
46
|
+
?? foreground) as HexColorToken
|
|
43
47
|
const resolvedColor = appearance === 'normal'
|
|
44
48
|
? baseColor
|
|
45
49
|
: theme.semantics.withAppearance({ color: baseColor, appearance })
|
|
@@ -64,7 +68,7 @@ export const ThemedIcon = ({
|
|
|
64
68
|
>
|
|
65
69
|
<Glyph
|
|
66
70
|
size={iconToken.size}
|
|
67
|
-
strokeWidth={strokeWidth ?? iconToken.strokeWidth}
|
|
71
|
+
strokeWidth={strokeWidth ?? iconStyle.strokeWidth ?? iconToken.strokeWidth}
|
|
68
72
|
color={resolvedColor}
|
|
69
73
|
/>
|
|
70
74
|
</View>
|
|
@@ -23,9 +23,13 @@ export const ThemedText = forwardRef<React.ComponentRef<typeof RNText>, ThemedTe
|
|
|
23
23
|
...props
|
|
24
24
|
}, ref) {
|
|
25
25
|
const { theme } = useTheme()
|
|
26
|
-
const {
|
|
26
|
+
const { foreground, textStyle } = useContentTheme()
|
|
27
|
+
// TODO use a hex color parser
|
|
28
|
+
const foregroundColor = (typeof textStyle.color === 'string'
|
|
29
|
+
? textStyle.color
|
|
30
|
+
: foreground) as HexColorToken
|
|
27
31
|
const color = appearance === 'description'
|
|
28
|
-
? theme.semantics.asDescription({ color: foregroundColor
|
|
32
|
+
? theme.semantics.asDescription({ color: foregroundColor })
|
|
29
33
|
: foregroundColor
|
|
30
34
|
|
|
31
35
|
return (
|
|
@@ -4,9 +4,12 @@ import {
|
|
|
4
4
|
} from 'react'
|
|
5
5
|
import type { ColorValue, TextStyle } from 'react-native'
|
|
6
6
|
|
|
7
|
+
import type { IconStyle } from '../../icons'
|
|
8
|
+
|
|
7
9
|
export type ContentThemeContextValue = {
|
|
8
|
-
|
|
10
|
+
foreground: ColorValue,
|
|
9
11
|
textStyle: TextStyle,
|
|
12
|
+
iconStyle: IconStyle,
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export const ContentThemeContext = createContext<ContentThemeContextValue | null>(null)
|
|
@@ -15,7 +18,7 @@ export const useContentTheme = (): ContentThemeContextValue => {
|
|
|
15
18
|
const context = useContext(ContentThemeContext)
|
|
16
19
|
if (!context) {
|
|
17
20
|
throw new Error(
|
|
18
|
-
'useContentTheme must be used within
|
|
21
|
+
'useContentTheme must be used within ContentThemeRootProvider. Try adding a ContentThemeRootProvider around your app.'
|
|
19
22
|
)
|
|
20
23
|
}
|
|
21
24
|
return context
|
|
@@ -2,27 +2,81 @@ import {
|
|
|
2
2
|
useMemo,
|
|
3
3
|
type PropsWithChildren
|
|
4
4
|
} from 'react'
|
|
5
|
-
import type {
|
|
5
|
+
import type { ColorValue, TextStyle } from 'react-native'
|
|
6
6
|
|
|
7
|
+
import type { IconStyle } from '../../icons'
|
|
7
8
|
import {
|
|
8
9
|
ContentThemeContext,
|
|
10
|
+
useContentTheme,
|
|
9
11
|
type ContentThemeContextValue
|
|
10
12
|
} from './ContentThemeContext'
|
|
11
13
|
|
|
12
|
-
export type
|
|
13
|
-
foregroundColor: ColorValue,
|
|
14
|
-
textStyle: TextStyle,
|
|
15
|
-
}
|
|
14
|
+
export type ContentThemeRootProviderProps = PropsWithChildren & ContentThemeContextValue
|
|
16
15
|
|
|
17
|
-
export const
|
|
16
|
+
export const ContentThemeRootProvider = ({
|
|
18
17
|
children,
|
|
19
|
-
|
|
18
|
+
foreground,
|
|
20
19
|
textStyle,
|
|
21
|
-
|
|
20
|
+
iconStyle,
|
|
21
|
+
}: ContentThemeRootProviderProps) => {
|
|
22
22
|
const value = useMemo((): ContentThemeContextValue => ({
|
|
23
|
-
|
|
23
|
+
foreground,
|
|
24
24
|
textStyle,
|
|
25
|
-
|
|
25
|
+
iconStyle,
|
|
26
|
+
}), [foreground, textStyle, iconStyle])
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<ContentThemeContext.Provider value={value}>
|
|
30
|
+
{children}
|
|
31
|
+
</ContentThemeContext.Provider>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type ForegroundOverride =
|
|
36
|
+
| ColorValue
|
|
37
|
+
| ((prev: ColorValue) => ColorValue)
|
|
38
|
+
|
|
39
|
+
type TextStyleOverride =
|
|
40
|
+
| TextStyle
|
|
41
|
+
| ((prev: TextStyle, foreground: ColorValue) => TextStyle)
|
|
42
|
+
|
|
43
|
+
type IconStyleOverride =
|
|
44
|
+
| IconStyle
|
|
45
|
+
| ((prev: IconStyle, foreground: ColorValue) => IconStyle)
|
|
46
|
+
|
|
47
|
+
export type ContentThemeOverrideProviderProps = PropsWithChildren & {
|
|
48
|
+
foreground?: ForegroundOverride,
|
|
49
|
+
textStyle?: TextStyleOverride,
|
|
50
|
+
iconStyle?: IconStyleOverride,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const ContentThemeOverrideProvider = ({
|
|
54
|
+
children,
|
|
55
|
+
foreground: foregroundOverride,
|
|
56
|
+
textStyle: textStyleOverride,
|
|
57
|
+
iconStyle: iconStyleOverride,
|
|
58
|
+
}: ContentThemeOverrideProviderProps) => {
|
|
59
|
+
const parent = useContentTheme()
|
|
60
|
+
|
|
61
|
+
const value = useMemo((): ContentThemeContextValue => {
|
|
62
|
+
const foreground = typeof foregroundOverride === 'function'
|
|
63
|
+
? foregroundOverride(parent.foreground)
|
|
64
|
+
: foregroundOverride ?? parent.foreground
|
|
65
|
+
|
|
66
|
+
const textStyle = typeof textStyleOverride === 'function'
|
|
67
|
+
? textStyleOverride(parent.textStyle, foreground)
|
|
68
|
+
: textStyleOverride ?? parent.textStyle
|
|
69
|
+
|
|
70
|
+
const iconStyle = typeof iconStyleOverride === 'function'
|
|
71
|
+
? iconStyleOverride(parent.iconStyle, foreground)
|
|
72
|
+
: iconStyleOverride ?? parent.iconStyle
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
foreground,
|
|
76
|
+
textStyle,
|
|
77
|
+
iconStyle,
|
|
78
|
+
}
|
|
79
|
+
}, [parent, foregroundOverride, textStyleOverride, iconStyleOverride])
|
|
26
80
|
|
|
27
81
|
return (
|
|
28
82
|
<ContentThemeContext.Provider value={value}>
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
import { useNativeKeyValueStore } from '../../hooks/useNativeKeyValueStore'
|
|
22
22
|
import type { ThemeMode } from '../../theme/themes/hightideThemes'
|
|
23
23
|
import type { HightideTheme } from '../../theme/types/theme'
|
|
24
|
-
import {
|
|
24
|
+
import { ContentThemeRootProvider } from '../content-theme'
|
|
25
25
|
|
|
26
26
|
export type ThemeProviderProps<T> = PropsWithChildren & {
|
|
27
27
|
theme?: ThemeMode | null,
|
|
@@ -93,12 +93,17 @@ export const ThemeProvider = ({
|
|
|
93
93
|
|
|
94
94
|
return (
|
|
95
95
|
<ThemeContext.Provider value={contextValue}>
|
|
96
|
-
<
|
|
97
|
-
|
|
96
|
+
<ContentThemeRootProvider
|
|
97
|
+
foreground={contextValue.theme.colors.surface.onColor}
|
|
98
98
|
textStyle={contextValue.theme.typography.body.md}
|
|
99
|
+
iconStyle={{
|
|
100
|
+
size: contextValue.theme.icongraphy.sizes.md,
|
|
101
|
+
strokeWidth: contextValue.theme.icongraphy.strokeWidth,
|
|
102
|
+
color: contextValue.theme.colors.surface.onColor,
|
|
103
|
+
}}
|
|
99
104
|
>
|
|
100
105
|
{children}
|
|
101
|
-
</
|
|
106
|
+
</ContentThemeRootProvider>
|
|
102
107
|
</ThemeContext.Provider>
|
|
103
108
|
)
|
|
104
109
|
}
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
ChatMessageBubbleMetaDataStatusContainerStyle,
|
|
26
26
|
ChatMessageBubbleMetaDataTextStyle,
|
|
27
27
|
PressableContainerStyle,
|
|
28
|
+
PressableIconStyle,
|
|
28
29
|
PressableState,
|
|
29
30
|
PressableStateLayerStyle,
|
|
30
31
|
PressableTextStyle
|
|
@@ -127,6 +128,9 @@ export const toChatAttachmentMessageBubbleThemeResolvers: ComponentThemeResolver
|
|
|
127
128
|
...toTextStyle(resolvePressable(pressableState).text),
|
|
128
129
|
...toOptionalTextStyle(contentContainer.text),
|
|
129
130
|
})),
|
|
131
|
+
icon: createValueResolver((pressableState: PressableState): PressableIconStyle => (
|
|
132
|
+
toIconStyle(resolvePressable(pressableState).icon)
|
|
133
|
+
)),
|
|
130
134
|
}
|
|
131
135
|
}),
|
|
132
136
|
fileIconContainer: createStyleResolver((
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ContainerTokens,
|
|
3
|
+
IconTokens,
|
|
3
4
|
TextStyleTokens
|
|
4
5
|
} from '@helpwave/hightide-design/component-token-resolvers'
|
|
5
6
|
|
|
6
7
|
import { toContainerStyle } from '../../adapters/container-adapter'
|
|
8
|
+
import { toIconStyle } from '../../adapters/icon-style-adapter'
|
|
7
9
|
import { toTextStyle } from '../../adapters/text-style-adapter'
|
|
8
10
|
import type {
|
|
9
11
|
ChatQuickReplyChipState,
|
|
10
12
|
ChatQuickReplyChipThemeResolvers,
|
|
11
13
|
PressableContainerStyle,
|
|
14
|
+
PressableIconStyle,
|
|
12
15
|
PressableState,
|
|
13
16
|
PressableStateLayerStyle,
|
|
14
17
|
PressableTextStyle
|
|
@@ -28,6 +31,10 @@ const toOptionalTextStyle = (tokens?: TextStyleTokens): PressableTextStyle => (
|
|
|
28
31
|
tokens === undefined ? {} : toTextStyle(tokens)
|
|
29
32
|
)
|
|
30
33
|
|
|
34
|
+
const toOptionalIconStyle = (tokens?: IconTokens): PressableIconStyle => (
|
|
35
|
+
tokens === undefined ? {} : toIconStyle(tokens)
|
|
36
|
+
)
|
|
37
|
+
|
|
31
38
|
export const toChatQuickReplyChipThemeResolvers: ComponentThemeResolver<ChatQuickReplyChipThemeResolvers> = ({
|
|
32
39
|
themeTokens,
|
|
33
40
|
semanticTokens,
|
|
@@ -74,6 +81,10 @@ export const toChatQuickReplyChipThemeResolvers: ComponentThemeResolver<ChatQuic
|
|
|
74
81
|
...toTextStyle(resolvePressable(pressableState).text),
|
|
75
82
|
...toOptionalTextStyle(tokens.text),
|
|
76
83
|
})),
|
|
84
|
+
icon: createValueResolver((pressableState: PressableState): PressableIconStyle => ({
|
|
85
|
+
...toIconStyle(resolvePressable(pressableState).icon),
|
|
86
|
+
...toOptionalIconStyle(tokens.icon),
|
|
87
|
+
})),
|
|
77
88
|
}
|
|
78
89
|
}),
|
|
79
90
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { toContainerStyle } from '../adapters/container-adapter'
|
|
2
|
+
import { toIconStyle } from '../adapters/icon-style-adapter'
|
|
2
3
|
import { toTextStyle } from '../adapters/text-style-adapter'
|
|
3
4
|
import type {
|
|
5
|
+
ChipIconStyle,
|
|
4
6
|
ChipState,
|
|
5
7
|
ChipStyle,
|
|
6
8
|
ChipTextStyle,
|
|
@@ -8,6 +10,7 @@ import type {
|
|
|
8
10
|
} from '../types/components/chip'
|
|
9
11
|
import {
|
|
10
12
|
createStyleResolver,
|
|
13
|
+
createValueResolver,
|
|
11
14
|
type ComponentThemeResolver
|
|
12
15
|
} from '../types/resolver'
|
|
13
16
|
|
|
@@ -30,6 +33,9 @@ export const toChipThemeResolvers: ComponentThemeResolver<ChipThemeResolvers> =
|
|
|
30
33
|
chip: createStyleResolver((state: ChipState): ChipStyle => (
|
|
31
34
|
toContainerStyle(resolve(state).container)
|
|
32
35
|
)),
|
|
36
|
+
icon: createValueResolver((state: ChipState): ChipIconStyle => (
|
|
37
|
+
toIconStyle(resolve(state).icon)
|
|
38
|
+
)),
|
|
33
39
|
text: createStyleResolver((state: ChipState): ChipTextStyle => (
|
|
34
40
|
toTextStyle(resolve(state).text)
|
|
35
41
|
)),
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { toContainerStyle } from '../adapters/container-adapter'
|
|
2
2
|
import { toIconStyle } from '../adapters/icon-style-adapter'
|
|
3
|
-
import { toTextStyle } from '../adapters/text-style-adapter'
|
|
4
3
|
import type {
|
|
5
4
|
IconButtonIconStyle,
|
|
6
5
|
IconButtonState,
|
|
7
6
|
IconButtonStyle,
|
|
8
|
-
IconButtonTextStyle,
|
|
9
7
|
IconButtonThemeResolvers
|
|
10
8
|
} from '../types/components/iconButton'
|
|
11
9
|
import {
|
|
@@ -49,8 +47,5 @@ export const toIconButtonThemeResolvers: ComponentThemeResolver<IconButtonThemeR
|
|
|
49
47
|
icon: createValueResolver((state: IconButtonState): IconButtonIconStyle => (
|
|
50
48
|
toIconStyle(resolve(state).icon)
|
|
51
49
|
)),
|
|
52
|
-
text: createStyleResolver((state: IconButtonState): IconButtonTextStyle => (
|
|
53
|
-
toTextStyle(resolve(state).text)
|
|
54
|
-
)),
|
|
55
50
|
}
|
|
56
51
|
}
|
|
@@ -3,6 +3,7 @@ import { toIconStyle } from '../adapters/icon-style-adapter'
|
|
|
3
3
|
import { toTextStyle } from '../adapters/text-style-adapter'
|
|
4
4
|
import type {
|
|
5
5
|
ListActionItemContentStyle,
|
|
6
|
+
ListActionItemDescriptionStyle,
|
|
6
7
|
ListActionItemIconStyle,
|
|
7
8
|
ListActionItemLeadingItemContainerStyle,
|
|
8
9
|
ListActionItemState,
|
|
@@ -98,6 +99,9 @@ const toListActionItemThemeResolvers: ComponentThemeResolver<ListActionItemTheme
|
|
|
98
99
|
titleText: createStyleResolver((state: ListActionItemState): ListActionItemTitleStyle => (
|
|
99
100
|
toTextStyle(resolve(state).titleText)
|
|
100
101
|
)),
|
|
102
|
+
descriptionText: createStyleResolver((state: ListActionItemState): ListActionItemDescriptionStyle => (
|
|
103
|
+
toTextStyle(resolve(state).descriptionText)
|
|
104
|
+
)),
|
|
101
105
|
icon: createValueResolver((state: ListActionItemState): ListActionItemIconStyle => (
|
|
102
106
|
toIconStyle(resolve(state).icon)
|
|
103
107
|
)),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { toContainerStyle } from '../adapters/container-adapter'
|
|
2
|
+
import { toIconStyle } from '../adapters/icon-style-adapter'
|
|
2
3
|
import { toTextStyle } from '../adapters/text-style-adapter'
|
|
3
4
|
import type {
|
|
5
|
+
ThemedPressableIconStyle,
|
|
4
6
|
ThemedPressableState,
|
|
5
7
|
ThemedPressableStyle,
|
|
6
8
|
ThemedPressableTextStyle,
|
|
@@ -8,6 +10,7 @@ import type {
|
|
|
8
10
|
} from '../types/components/themedPressable'
|
|
9
11
|
import {
|
|
10
12
|
createStyleResolver,
|
|
13
|
+
createValueResolver,
|
|
11
14
|
toPressableInteractionState,
|
|
12
15
|
type ComponentThemeResolver
|
|
13
16
|
} from '../types/resolver'
|
|
@@ -47,6 +50,9 @@ export const toThemedPressableThemeResolvers: ComponentThemeResolver<ThemedPress
|
|
|
47
50
|
left: 0,
|
|
48
51
|
}
|
|
49
52
|
}),
|
|
53
|
+
icon: createValueResolver((state: ThemedPressableState): ThemedPressableIconStyle => (
|
|
54
|
+
toIconStyle(resolve(state).icon)
|
|
55
|
+
)),
|
|
50
56
|
text: createStyleResolver((state: ThemedPressableState): ThemedPressableTextStyle => (
|
|
51
57
|
toTextStyle(resolve(state).text)
|
|
52
58
|
)),
|
|
@@ -61,6 +61,7 @@ export type ChatAttachmentMessageBubbleState = {
|
|
|
61
61
|
export type PressableContainerStyle = ViewStyle
|
|
62
62
|
export type PressableStateLayerStyle = ViewStyle
|
|
63
63
|
export type PressableTextStyle = TextStyle
|
|
64
|
+
export type PressableIconStyle = IconStyle
|
|
64
65
|
|
|
65
66
|
export type PressableState = ThemedPressableState
|
|
66
67
|
|
|
@@ -158,6 +159,10 @@ export type ChatAttachmentMessageBubbleThemeResolvers = {
|
|
|
158
159
|
PressableState,
|
|
159
160
|
PressableTextStyle
|
|
160
161
|
>,
|
|
162
|
+
icon: StyleResolverFunction<
|
|
163
|
+
PressableState,
|
|
164
|
+
PressableIconStyle
|
|
165
|
+
>,
|
|
161
166
|
}
|
|
162
167
|
>,
|
|
163
168
|
fileIconContainer: StyleResolverFunction<ChatAttachmentMessageBubbleState, ChatAttachmentMessageBubbleFileIconContainerStyle>,
|
|
@@ -195,6 +200,10 @@ export type ChatQuickReplyChipThemeResolvers = {
|
|
|
195
200
|
PressableState,
|
|
196
201
|
PressableTextStyle
|
|
197
202
|
>,
|
|
203
|
+
icon: StyleResolverFunction<
|
|
204
|
+
PressableState,
|
|
205
|
+
PressableIconStyle
|
|
206
|
+
>,
|
|
198
207
|
}
|
|
199
208
|
>,
|
|
200
209
|
}
|
|
@@ -7,6 +7,7 @@ import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
|
7
7
|
import type { ChipVariant, ComponentSize } from '@helpwave/hightide-design/semantic-token-resolvers'
|
|
8
8
|
|
|
9
9
|
import type { StyleResolverFunction } from '../resolver'
|
|
10
|
+
import type { IconStyle } from '../../../icons'
|
|
10
11
|
|
|
11
12
|
export type ChipState = {
|
|
12
13
|
size?: ComponentSize,
|
|
@@ -18,7 +19,10 @@ export type ChipStyle = ViewStyle
|
|
|
18
19
|
|
|
19
20
|
export type ChipTextStyle = TextStyle
|
|
20
21
|
|
|
22
|
+
export type ChipIconStyle = IconStyle
|
|
23
|
+
|
|
21
24
|
export type ChipThemeResolvers = {
|
|
22
25
|
chip: StyleResolverFunction<ChipState, ChipStyle>,
|
|
26
|
+
icon: StyleResolverFunction<ChipState, ChipIconStyle>,
|
|
23
27
|
text: StyleResolverFunction<ChipState, ChipTextStyle>,
|
|
24
28
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
TextStyle,
|
|
3
|
-
ViewStyle
|
|
4
|
-
} from 'react-native'
|
|
1
|
+
import type { ViewStyle } from 'react-native'
|
|
5
2
|
|
|
6
3
|
import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens'
|
|
7
4
|
import type {
|
|
@@ -25,11 +22,8 @@ export type IconButtonStyle = ViewStyle
|
|
|
25
22
|
|
|
26
23
|
export type IconButtonIconStyle = IconStyle
|
|
27
24
|
|
|
28
|
-
export type IconButtonTextStyle = TextStyle
|
|
29
|
-
|
|
30
25
|
export type IconButtonThemeResolvers = {
|
|
31
26
|
container: StyleResolverFunction<IconButtonState, IconButtonStyle>,
|
|
32
27
|
stateLayer: StyleResolverFunction<IconButtonState, IconButtonStyle>,
|
|
33
28
|
icon: StyleResolverFunction<IconButtonState, IconButtonIconStyle>,
|
|
34
|
-
text: StyleResolverFunction<IconButtonState, IconButtonTextStyle>,
|
|
35
29
|
}
|
|
@@ -52,6 +52,8 @@ export type ListActionItemTrailingItemContainerStyle = ViewStyle
|
|
|
52
52
|
|
|
53
53
|
export type ListActionItemTitleStyle = TextStyle
|
|
54
54
|
|
|
55
|
+
export type ListActionItemDescriptionStyle = TextStyle
|
|
56
|
+
|
|
55
57
|
export type ListActionItemIconStyle = IconStyle
|
|
56
58
|
|
|
57
59
|
export type ListActionItemThemeResolvers = {
|
|
@@ -60,6 +62,7 @@ export type ListActionItemThemeResolvers = {
|
|
|
60
62
|
content: StyleResolverFunction<ListActionItemState, ListActionItemContentStyle>,
|
|
61
63
|
trailingItemContainer: StyleResolverFunction<ListActionItemState, ListActionItemTrailingItemContainerStyle>,
|
|
62
64
|
titleText: StyleResolverFunction<ListActionItemState, ListActionItemTitleStyle>,
|
|
65
|
+
descriptionText: StyleResolverFunction<ListActionItemState, ListActionItemDescriptionStyle>,
|
|
63
66
|
icon: StyleResolverFunction<ListActionItemState, ListActionItemIconStyle>,
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -75,6 +78,8 @@ export type ListNavigationItemTrailingItemContainerStyle = ListActionItemTrailin
|
|
|
75
78
|
|
|
76
79
|
export type ListNavigationItemTitleStyle = ListActionItemTitleStyle
|
|
77
80
|
|
|
81
|
+
export type ListNavigationItemDescriptionStyle = ListActionItemDescriptionStyle
|
|
82
|
+
|
|
78
83
|
export type ListNavigationItemIconStyle = ListActionItemIconStyle
|
|
79
84
|
|
|
80
85
|
export type ListNavigationItemThemeResolvers = ListActionItemThemeResolvers
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
InteractionState,
|
|
12
12
|
StyleResolverFunction
|
|
13
13
|
} from '../resolver'
|
|
14
|
+
import type { IconStyle } from '../../../icons'
|
|
14
15
|
|
|
15
16
|
export type ThemedPressableState = InteractionState & {
|
|
16
17
|
size?: ComponentSize,
|
|
@@ -24,8 +25,11 @@ export type ThemedPressableStyle = ViewStyle
|
|
|
24
25
|
|
|
25
26
|
export type ThemedPressableTextStyle = TextStyle
|
|
26
27
|
|
|
28
|
+
export type ThemedPressableIconStyle = IconStyle
|
|
29
|
+
|
|
27
30
|
export type ThemedPressableThemeResolvers = {
|
|
28
31
|
container: StyleResolverFunction<ThemedPressableState, ThemedPressableStyle>,
|
|
29
32
|
stateLayer: StyleResolverFunction<ThemedPressableState, ThemedPressableStyle>,
|
|
33
|
+
icon: StyleResolverFunction<ThemedPressableState, ThemedPressableIconStyle>,
|
|
30
34
|
text: StyleResolverFunction<ThemedPressableState, ThemedPressableTextStyle>,
|
|
31
35
|
}
|