@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
|
@@ -4,7 +4,9 @@ import type { StyleProp, TextStyle } from 'react-native'
|
|
|
4
4
|
|
|
5
5
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import type { ListItemContentOrder } from '../../enums/listItemContentOrder'
|
|
8
|
+
|
|
9
|
+
export type { ListItemContentOrder }
|
|
8
10
|
|
|
9
11
|
export type ListItemTextContentProps = {
|
|
10
12
|
title?: string,
|
|
@@ -25,7 +27,7 @@ export const ListItemTextContent = ({
|
|
|
25
27
|
subtitleStyle?: StyleProp<TextStyle>,
|
|
26
28
|
}) => {
|
|
27
29
|
if (content != null) {
|
|
28
|
-
return
|
|
30
|
+
return <Fragment>{content}</Fragment>
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
const titleNode = title != null
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
useMemo,
|
|
3
|
+
useState,
|
|
3
4
|
type ReactNode
|
|
4
5
|
} from 'react'
|
|
5
6
|
import {
|
|
@@ -16,6 +17,7 @@ import { HightideIconRegistry } from '../../icons/HightideIconRegistry'
|
|
|
16
17
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
17
18
|
import { useDebugContext } from '../../global-contexts/debug'
|
|
18
19
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
20
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
19
21
|
import type {
|
|
20
22
|
ListNavigationItemDescriptionStyle,
|
|
21
23
|
ListNavigationItemState,
|
|
@@ -44,13 +46,6 @@ export type ListNavigationItemProps = Omit<PressableProps, 'children' | 'style'>
|
|
|
44
46
|
subtitleStyle?: StyleOverwrite<ListNavigationItemState, ListNavigationItemDescriptionStyle>,
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
type PressableInteraction = {
|
|
48
|
-
pressed: boolean,
|
|
49
|
-
hovered?: boolean,
|
|
50
|
-
focused?: boolean,
|
|
51
|
-
focusVisible?: boolean,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
49
|
export const ListNavigationItem = ({
|
|
55
50
|
title,
|
|
56
51
|
subtitle,
|
|
@@ -74,15 +69,21 @@ export const ListNavigationItem = ({
|
|
|
74
69
|
hitSlop: providedHitSlop,
|
|
75
70
|
onLayout: providedOnLayout,
|
|
76
71
|
})
|
|
72
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
77
73
|
|
|
78
|
-
const
|
|
74
|
+
const resolvedState = useMemo((): ListNavigationItemState => ({
|
|
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.navigation.container, resolvedState, itemStyle)
|
|
81
|
+
const resolvedLeadingItemContainerStyle = useMemoizedTheme(theme.components.listItem.navigation.leadingItemContainer, resolvedState)
|
|
82
|
+
const resolvedContentStyle = useMemoizedTheme(theme.components.listItem.navigation.content, resolvedState)
|
|
83
|
+
const resolvedTrailingItemContainerStyle = useMemoizedTheme(theme.components.listItem.navigation.trailingItemContainer, resolvedState)
|
|
84
|
+
const resolvedTitleStyle = useMemoizedTheme(theme.components.listItem.navigation.titleText, resolvedState, titleStyle)
|
|
85
|
+
const resolvedSubtitleStyle = useMemoizedTheme(theme.components.listItem.navigation.descriptionText, resolvedState, subtitleStyle)
|
|
86
|
+
const resolvedIconStyle = useMemoizedTheme(theme.components.listItem.navigation.icon, resolvedState)
|
|
86
87
|
|
|
87
88
|
return (
|
|
88
89
|
<Pressable
|
|
@@ -90,57 +91,48 @@ export const ListNavigationItem = ({
|
|
|
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.navigation.leadingItemContainer(state)
|
|
101
|
-
const resolvedContentStyle = theme.components.listItem.navigation.content(state)
|
|
102
|
-
const resolvedTrailingItemContainerStyle = theme.components.listItem.navigation.trailingItemContainer(state)
|
|
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)
|
|
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
|
-
<ListItemAccessory
|
|
135
|
-
style={resolvedTrailingItemContainerStyle}
|
|
136
|
-
foreground={color?.onColor}
|
|
137
|
-
iconStyle={resolvedIconStyle}
|
|
138
|
-
>
|
|
139
|
-
<ThemedIcon icon={HightideIconRegistry.ChevronRight} />
|
|
140
|
-
</ListItemAccessory>
|
|
141
|
-
</Fragment>
|
|
142
|
-
)
|
|
99
|
+
onPressOut={(event) => {
|
|
100
|
+
setIsPressed(false)
|
|
101
|
+
props.onPressOut?.(event)
|
|
143
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
|
+
<ListItemAccessory
|
|
130
|
+
style={resolvedTrailingItemContainerStyle}
|
|
131
|
+
foreground={color?.onColor}
|
|
132
|
+
iconStyle={resolvedIconStyle}
|
|
133
|
+
>
|
|
134
|
+
<ThemedIcon icon={HightideIconRegistry.ChevronRight} />
|
|
135
|
+
</ListItemAccessory>
|
|
144
136
|
</Pressable>
|
|
145
137
|
)
|
|
146
138
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { forwardRef, useMemo, useState } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Pressable,
|
|
4
4
|
View,
|
|
@@ -22,6 +22,7 @@ import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
|
|
|
22
22
|
import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
|
|
23
23
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
24
24
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
25
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
25
26
|
|
|
26
27
|
export type ButtonSize = ComponentSize
|
|
27
28
|
|
|
@@ -45,13 +46,6 @@ export type ButtonProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
|
45
46
|
iconStyle?: StyleOverwrite<ButtonState, IconStyle>,
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
type PressableInteraction = {
|
|
49
|
-
pressed: boolean,
|
|
50
|
-
hovered?: boolean,
|
|
51
|
-
focused?: boolean,
|
|
52
|
-
focusVisible?: boolean,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
49
|
export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonProps>(function Button({
|
|
56
50
|
children,
|
|
57
51
|
size = 'md',
|
|
@@ -76,16 +70,19 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
|
|
|
76
70
|
onLayout: providedOnLayout,
|
|
77
71
|
})
|
|
78
72
|
|
|
79
|
-
const
|
|
73
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
74
|
+
const resolvedState = useMemo(() => ({
|
|
80
75
|
size,
|
|
81
76
|
color,
|
|
82
77
|
variant,
|
|
83
78
|
isDisabled: !!disabled,
|
|
84
|
-
isPressed:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
isPressed: isPressed,
|
|
80
|
+
}), [color, disabled, isPressed, size, variant])
|
|
81
|
+
|
|
82
|
+
const resolvedContainerStyle = useMemoizedTheme(theme.components.button.container, resolvedState, style)
|
|
83
|
+
const resolvedTextStyle = useMemoizedTheme(theme.components.button.text, resolvedState, textStyle)
|
|
84
|
+
const resolvedIcon = useMemoizedTheme(theme.components.button.icon, resolvedState, iconStyle)
|
|
85
|
+
const resolvedStateLayerStyle = useMemoizedTheme(theme.components.button.stateLayer, resolvedState, stateLayerStyle)
|
|
89
86
|
|
|
90
87
|
return (
|
|
91
88
|
<Pressable
|
|
@@ -94,43 +91,40 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
|
|
|
94
91
|
disabled={disabled}
|
|
95
92
|
hitSlop={hitSlop}
|
|
96
93
|
onLayout={onLayout}
|
|
97
|
-
style={
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
style={resolvedContainerStyle}
|
|
95
|
+
onPressIn={(event) => {
|
|
96
|
+
setIsPressed(true)
|
|
97
|
+
props.onPressIn?.(event)
|
|
100
98
|
}}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const resolvedText = theme.components.button.text(state, textStyle)
|
|
105
|
-
const resolvedIcon = theme.components.button.icon(state, iconStyle)
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<Fragment>
|
|
109
|
-
{hitBox.isVisualizing && (
|
|
110
|
-
<View
|
|
111
|
-
pointerEvents="none"
|
|
112
|
-
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
113
|
-
/>
|
|
114
|
-
)}
|
|
115
|
-
<View
|
|
116
|
-
pointerEvents="none"
|
|
117
|
-
style={theme.components.button.stateLayer(state, stateLayerStyle)}
|
|
118
|
-
/>
|
|
119
|
-
<ContentThemeOverrideProvider
|
|
120
|
-
textStyle={resolvedText}
|
|
121
|
-
iconStyle={resolvedIcon}
|
|
122
|
-
>
|
|
123
|
-
{leadingIcon !== undefined && (
|
|
124
|
-
<ThemedIcon icon={leadingIcon} />
|
|
125
|
-
)}
|
|
126
|
-
<ThemedText>{children}</ThemedText>
|
|
127
|
-
{trailingIcon !== undefined && (
|
|
128
|
-
<ThemedIcon icon={trailingIcon} />
|
|
129
|
-
)}
|
|
130
|
-
</ContentThemeOverrideProvider>
|
|
131
|
-
</Fragment>
|
|
132
|
-
)
|
|
99
|
+
onPressOut={(event) => {
|
|
100
|
+
setIsPressed(false)
|
|
101
|
+
props.onPressOut?.(event)
|
|
133
102
|
}}
|
|
103
|
+
>
|
|
104
|
+
{hitBox.isVisualizing && (
|
|
105
|
+
<View
|
|
106
|
+
pointerEvents="none"
|
|
107
|
+
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
<View
|
|
111
|
+
pointerEvents="none"
|
|
112
|
+
style={resolvedStateLayerStyle}
|
|
113
|
+
/>
|
|
114
|
+
<ContentThemeOverrideProvider
|
|
115
|
+
foreground={resolvedTextStyle?.color}
|
|
116
|
+
background={resolvedContainerStyle?.backgroundColor}
|
|
117
|
+
textStyle={resolvedTextStyle}
|
|
118
|
+
iconStyle={resolvedIcon}
|
|
119
|
+
>
|
|
120
|
+
{leadingIcon !== undefined && (
|
|
121
|
+
<ThemedIcon icon={leadingIcon} />
|
|
122
|
+
)}
|
|
123
|
+
<ThemedText>{children}</ThemedText>
|
|
124
|
+
{trailingIcon !== undefined && (
|
|
125
|
+
<ThemedIcon icon={trailingIcon} />
|
|
126
|
+
)}
|
|
127
|
+
</ContentThemeOverrideProvider>
|
|
134
128
|
</Pressable>
|
|
135
129
|
)
|
|
136
130
|
})
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Fragment,
|
|
3
|
-
useCallback
|
|
4
|
-
} from 'react'
|
|
1
|
+
import { useCallback, useMemo, useState } from 'react'
|
|
5
2
|
import {
|
|
6
3
|
Pressable,
|
|
7
4
|
View,
|
|
@@ -19,6 +16,7 @@ import { HightideIconRegistry } from '../../icons/HightideIconRegistry'
|
|
|
19
16
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
20
17
|
import { useDebugContext } from '../../global-contexts/debug'
|
|
21
18
|
import { useTheme } from '../../global-contexts/theme/ThemeContext'
|
|
19
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
22
20
|
import type {
|
|
23
21
|
CheckboxSize,
|
|
24
22
|
CheckboxState,
|
|
@@ -47,13 +45,6 @@ export type CheckboxProps = Omit<PressableProps, 'children' | 'style'>
|
|
|
47
45
|
stateLayerStyle?: StyleOverwrite<CheckboxState, CheckboxStateLayerStyle>,
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
type PressableInteraction = {
|
|
51
|
-
pressed: boolean,
|
|
52
|
-
hovered?: boolean,
|
|
53
|
-
focused?: boolean,
|
|
54
|
-
focusVisible?: boolean,
|
|
55
|
-
}
|
|
56
|
-
|
|
57
48
|
export const Checkbox = ({
|
|
58
49
|
value: controlledValue,
|
|
59
50
|
initialValue = false,
|
|
@@ -81,6 +72,7 @@ export const Checkbox = ({
|
|
|
81
72
|
onLayout: providedOnLayout,
|
|
82
73
|
})
|
|
83
74
|
const interactive = !disabled && !readOnly
|
|
75
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
84
76
|
|
|
85
77
|
const onEditCompleteStable = useEventCallbackStabilizer(onEditComplete)
|
|
86
78
|
const onValueChangeStable = useEventCallbackStabilizer(onValueChange)
|
|
@@ -96,7 +88,7 @@ export const Checkbox = ({
|
|
|
96
88
|
defaultValue: initialValue,
|
|
97
89
|
})
|
|
98
90
|
|
|
99
|
-
const
|
|
91
|
+
const resolvedState = useMemo((): CheckboxState => ({
|
|
100
92
|
size,
|
|
101
93
|
color,
|
|
102
94
|
isChecked: value,
|
|
@@ -105,11 +97,23 @@ export const Checkbox = ({
|
|
|
105
97
|
isDisabled: disabled,
|
|
106
98
|
isReadonly: readOnly,
|
|
107
99
|
isRounded,
|
|
108
|
-
isPressed
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
isPressed,
|
|
101
|
+
}), [
|
|
102
|
+
size,
|
|
103
|
+
color,
|
|
104
|
+
value,
|
|
105
|
+
indeterminate,
|
|
106
|
+
invalid,
|
|
107
|
+
disabled,
|
|
108
|
+
readOnly,
|
|
109
|
+
isRounded,
|
|
110
|
+
isPressed,
|
|
111
|
+
])
|
|
112
|
+
|
|
113
|
+
const resolvedContainerStyle = useMemoizedTheme(theme.components.checkbox.container, resolvedState, containerStyle)
|
|
114
|
+
const resolvedStateLayerStyle = useMemoizedTheme(theme.components.checkbox.stateLayer, resolvedState, stateLayerStyle)
|
|
115
|
+
const resolvedIcon = useMemoizedTheme(theme.components.checkbox.icon, resolvedState)
|
|
116
|
+
const showIcon = !!(indeterminate || value)
|
|
113
117
|
|
|
114
118
|
return (
|
|
115
119
|
<Pressable
|
|
@@ -122,44 +126,39 @@ export const Checkbox = ({
|
|
|
122
126
|
}}
|
|
123
127
|
hitSlop={hitSlop}
|
|
124
128
|
onLayout={onLayout}
|
|
129
|
+
style={[resolvedContainerStyle, style]}
|
|
130
|
+
onPressIn={(event) => {
|
|
131
|
+
setIsPressed(true)
|
|
132
|
+
props.onPressIn?.(event)
|
|
133
|
+
}}
|
|
134
|
+
onPressOut={(event) => {
|
|
135
|
+
setIsPressed(false)
|
|
136
|
+
props.onPressOut?.(event)
|
|
137
|
+
}}
|
|
125
138
|
onPress={(event) => {
|
|
126
139
|
if (interactive) {
|
|
127
140
|
setValue((previous) => !previous)
|
|
128
141
|
}
|
|
129
142
|
props.onPress?.(event)
|
|
130
143
|
}}
|
|
131
|
-
style={(pressableState) => {
|
|
132
|
-
const state = resolveState(pressableState as PressableInteraction)
|
|
133
|
-
return [theme.components.checkbox.container(state, containerStyle), style]
|
|
134
|
-
}}
|
|
135
144
|
>
|
|
136
|
-
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
{showIcon && (
|
|
154
|
-
<ThemedIcon
|
|
155
|
-
icon={indeterminate ? HightideIconRegistry.Minus : HightideIconRegistry.Check}
|
|
156
|
-
size={resolvedIcon.size}
|
|
157
|
-
color={resolvedIcon.color}
|
|
158
|
-
/>
|
|
159
|
-
)}
|
|
160
|
-
</Fragment>
|
|
161
|
-
)
|
|
162
|
-
}}
|
|
145
|
+
{hitBox.isVisualizing && (
|
|
146
|
+
<View
|
|
147
|
+
pointerEvents="none"
|
|
148
|
+
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
149
|
+
/>
|
|
150
|
+
)}
|
|
151
|
+
<View
|
|
152
|
+
pointerEvents="none"
|
|
153
|
+
style={resolvedStateLayerStyle}
|
|
154
|
+
/>
|
|
155
|
+
{showIcon && (
|
|
156
|
+
<ThemedIcon
|
|
157
|
+
icon={indeterminate ? HightideIconRegistry.Minus : HightideIconRegistry.Check}
|
|
158
|
+
size={resolvedIcon.size}
|
|
159
|
+
color={resolvedIcon.color}
|
|
160
|
+
/>
|
|
161
|
+
)}
|
|
163
162
|
</Pressable>
|
|
164
163
|
)
|
|
165
164
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { forwardRef, useMemo, useState } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Pressable,
|
|
4
4
|
View,
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
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
|
+
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
16
17
|
import type {
|
|
17
18
|
IconButtonState,
|
|
18
19
|
IconButtonStyle
|
|
@@ -43,15 +44,8 @@ export type IconButtonProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
|
43
44
|
iconStyle?: StyleOverwrite<IconButtonState, IconStyle>,
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
type PressableInteraction = {
|
|
47
|
-
pressed: boolean,
|
|
48
|
-
hovered?: boolean,
|
|
49
|
-
focused?: boolean,
|
|
50
|
-
focusVisible?: boolean,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
47
|
export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconButtonProps>(function IconButton({
|
|
54
|
-
icon
|
|
48
|
+
icon,
|
|
55
49
|
size = 'md',
|
|
56
50
|
color,
|
|
57
51
|
variant = 'filled',
|
|
@@ -71,17 +65,25 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
71
65
|
hitSlop: providedHitSlop,
|
|
72
66
|
onLayout: providedOnLayout,
|
|
73
67
|
})
|
|
68
|
+
const [isPressed, setIsPressed] = useState(false)
|
|
74
69
|
|
|
75
|
-
const
|
|
70
|
+
const resolvedState = useMemo((): IconButtonState => ({
|
|
76
71
|
size,
|
|
77
72
|
color,
|
|
78
73
|
variant,
|
|
79
74
|
isDisabled: !!disabled,
|
|
80
|
-
isPressed
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
isPressed,
|
|
76
|
+
}), [
|
|
77
|
+
size,
|
|
78
|
+
color,
|
|
79
|
+
variant,
|
|
80
|
+
disabled,
|
|
81
|
+
isPressed,
|
|
82
|
+
])
|
|
83
|
+
|
|
84
|
+
const resolvedContainerStyle = useMemoizedTheme(theme.components.iconButton.container, resolvedState, style)
|
|
85
|
+
const resolvedStateLayerStyle = useMemoizedTheme(theme.components.iconButton.stateLayer, resolvedState, stateLayerStyle)
|
|
86
|
+
const resolvedIconStyle = useMemoizedTheme(theme.components.iconButton.icon, resolvedState, iconStyle)
|
|
85
87
|
|
|
86
88
|
return (
|
|
87
89
|
<Pressable
|
|
@@ -92,35 +94,31 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
92
94
|
accessibilityLabel={accessibilityLabel}
|
|
93
95
|
hitSlop={hitSlop}
|
|
94
96
|
onLayout={onLayout}
|
|
95
|
-
style={
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
style={resolvedContainerStyle}
|
|
98
|
+
onPressIn={(event) => {
|
|
99
|
+
setIsPressed(true)
|
|
100
|
+
props.onPressIn?.(event)
|
|
98
101
|
}}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const resolvedIcon = theme.components.iconButton.icon(state, iconStyle)
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<Fragment>
|
|
106
|
-
{hitBox.isVisualizing && (
|
|
107
|
-
<View
|
|
108
|
-
pointerEvents="none"
|
|
109
|
-
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
110
|
-
/>
|
|
111
|
-
)}
|
|
112
|
-
<View
|
|
113
|
-
pointerEvents="none"
|
|
114
|
-
style={theme.components.iconButton.stateLayer(state, stateLayerStyle)}
|
|
115
|
-
/>
|
|
116
|
-
<ContentThemeOverrideProvider
|
|
117
|
-
iconStyle={resolvedIcon}
|
|
118
|
-
>
|
|
119
|
-
<ThemedIcon icon={IconComponent} />
|
|
120
|
-
</ContentThemeOverrideProvider>
|
|
121
|
-
</Fragment>
|
|
122
|
-
)
|
|
102
|
+
onPressOut={(event) => {
|
|
103
|
+
setIsPressed(false)
|
|
104
|
+
props.onPressOut?.(event)
|
|
123
105
|
}}
|
|
106
|
+
>
|
|
107
|
+
{hitBox.isVisualizing && (
|
|
108
|
+
<View
|
|
109
|
+
pointerEvents="none"
|
|
110
|
+
style={createHitBoxOverlayStyle(hitSlop, hitBox.color)}
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
113
|
+
<View
|
|
114
|
+
pointerEvents="none"
|
|
115
|
+
style={resolvedStateLayerStyle}
|
|
116
|
+
/>
|
|
117
|
+
<ContentThemeOverrideProvider
|
|
118
|
+
iconStyle={resolvedIconStyle}
|
|
119
|
+
>
|
|
120
|
+
<ThemedIcon icon={icon} />
|
|
121
|
+
</ContentThemeOverrideProvider>
|
|
124
122
|
</Pressable>
|
|
125
123
|
)
|
|
126
124
|
})
|