@helpwave/hightide-native 0.9.1 → 0.9.2
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
CHANGED
|
@@ -22,6 +22,7 @@ import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
|
22
22
|
import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
|
|
23
23
|
import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
|
|
24
24
|
import { ThemedIcon } from '../visualization-and-display/ThemedIcon'
|
|
25
|
+
import { ThemedLoadingSpinner } from '../visualization-and-display/ThemedLoadingSpinner'
|
|
25
26
|
import { ThemedText } from '../visualization-and-display/ThemedText'
|
|
26
27
|
import { useMemoizedTheme } from '../../hooks/useMemoizedTheme'
|
|
27
28
|
|
|
@@ -46,6 +47,7 @@ export type ButtonProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
|
46
47
|
textStyle?: StyleOverwrite<ButtonState, ButtonTextStyle>,
|
|
47
48
|
textProps?: Omit<TextProps, 'style'>,
|
|
48
49
|
iconStyle?: StyleOverwrite<ButtonState, IconStyle>,
|
|
50
|
+
isProcessing?: boolean,
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonProps>(function Button({
|
|
@@ -61,6 +63,7 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
|
|
|
61
63
|
textStyle,
|
|
62
64
|
textProps,
|
|
63
65
|
iconStyle,
|
|
66
|
+
isProcessing = false,
|
|
64
67
|
hitSlop: providedHitSlop,
|
|
65
68
|
onLayout: providedOnLayout,
|
|
66
69
|
...props
|
|
@@ -86,20 +89,38 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
|
|
|
86
89
|
const resolvedTextStyle = useMemoizedTheme(theme.components.button.text, resolvedState, textStyle)
|
|
87
90
|
const resolvedIcon = useMemoizedTheme(theme.components.button.icon, resolvedState, iconStyle)
|
|
88
91
|
const resolvedStateLayerStyle = useMemoizedTheme(theme.components.button.stateLayer, resolvedState, stateLayerStyle)
|
|
92
|
+
const showLeadingSpinner = isProcessing && (leadingIcon !== undefined || trailingIcon === undefined)
|
|
93
|
+
const showTrailingSpinner = isProcessing && leadingIcon === undefined && trailingIcon !== undefined
|
|
89
94
|
|
|
90
95
|
return (
|
|
91
96
|
<Pressable
|
|
92
97
|
{...props}
|
|
93
98
|
ref={ref}
|
|
94
99
|
disabled={disabled}
|
|
100
|
+
accessibilityState={{
|
|
101
|
+
disabled: !!disabled,
|
|
102
|
+
busy: isProcessing,
|
|
103
|
+
}}
|
|
95
104
|
hitSlop={hitSlop}
|
|
96
105
|
onLayout={onLayout}
|
|
97
106
|
style={resolvedContainerStyle}
|
|
107
|
+
onPress={(event) => {
|
|
108
|
+
if (isProcessing) {
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
props.onPress?.(event)
|
|
112
|
+
}}
|
|
98
113
|
onPressIn={(event) => {
|
|
114
|
+
if (isProcessing) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
99
117
|
setIsPressed(true)
|
|
100
118
|
props.onPressIn?.(event)
|
|
101
119
|
}}
|
|
102
120
|
onPressOut={(event) => {
|
|
121
|
+
if (isProcessing) {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
103
124
|
setIsPressed(false)
|
|
104
125
|
props.onPressOut?.(event)
|
|
105
126
|
}}
|
|
@@ -120,11 +141,17 @@ export const Button = forwardRef<React.ComponentRef<typeof Pressable>, ButtonPro
|
|
|
120
141
|
textStyle={resolvedTextStyle}
|
|
121
142
|
iconStyle={resolvedIcon}
|
|
122
143
|
>
|
|
123
|
-
{
|
|
144
|
+
{showLeadingSpinner && (
|
|
145
|
+
<ThemedLoadingSpinner />
|
|
146
|
+
)}
|
|
147
|
+
{!isProcessing && leadingIcon !== undefined && (
|
|
124
148
|
<ThemedIcon icon={leadingIcon} />
|
|
125
149
|
)}
|
|
126
150
|
<ThemedText numberOfLines={1} ellipsizeMode="tail" {...textProps}>{children}</ThemedText>
|
|
127
|
-
{
|
|
151
|
+
{showTrailingSpinner && (
|
|
152
|
+
<ThemedLoadingSpinner />
|
|
153
|
+
)}
|
|
154
|
+
{!isProcessing && trailingIcon !== undefined && (
|
|
128
155
|
<ThemedIcon icon={trailingIcon} />
|
|
129
156
|
)}
|
|
130
157
|
</ContentThemeOverrideProvider>
|
|
@@ -22,7 +22,7 @@ import type { StyleOverwrite } from '../../theme/types/resolver'
|
|
|
22
22
|
import type { IconComponent, IconStyle } from '../../icons'
|
|
23
23
|
import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay'
|
|
24
24
|
import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop'
|
|
25
|
-
import { ThemedIcon } from '../visualization-and-display'
|
|
25
|
+
import { ThemedIcon, ThemedLoadingSpinner } from '../visualization-and-display'
|
|
26
26
|
|
|
27
27
|
export type IconButtonSize = ComponentSize
|
|
28
28
|
|
|
@@ -42,6 +42,7 @@ export type IconButtonProps = Omit<PressableProps, 'children' | 'style'> & {
|
|
|
42
42
|
style?: StyleOverwrite<IconButtonState, IconButtonStyle>,
|
|
43
43
|
stateLayerStyle?: StyleOverwrite<IconButtonState, IconButtonStyle>,
|
|
44
44
|
iconStyle?: StyleOverwrite<IconButtonState, IconStyle>,
|
|
45
|
+
isProcessing?: boolean,
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconButtonProps>(function IconButton({
|
|
@@ -54,6 +55,7 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
54
55
|
style,
|
|
55
56
|
stateLayerStyle,
|
|
56
57
|
iconStyle,
|
|
58
|
+
isProcessing = false,
|
|
57
59
|
hitSlop: providedHitSlop,
|
|
58
60
|
onLayout: providedOnLayout,
|
|
59
61
|
...props
|
|
@@ -92,14 +94,30 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
92
94
|
disabled={disabled}
|
|
93
95
|
accessibilityRole="button"
|
|
94
96
|
accessibilityLabel={accessibilityLabel}
|
|
97
|
+
accessibilityState={{
|
|
98
|
+
disabled: !!disabled,
|
|
99
|
+
busy: isProcessing,
|
|
100
|
+
}}
|
|
95
101
|
hitSlop={hitSlop}
|
|
96
102
|
onLayout={onLayout}
|
|
97
103
|
style={resolvedContainerStyle}
|
|
104
|
+
onPress={(event) => {
|
|
105
|
+
if (isProcessing) {
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
props.onPress?.(event)
|
|
109
|
+
}}
|
|
98
110
|
onPressIn={(event) => {
|
|
111
|
+
if (isProcessing) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
99
114
|
setIsPressed(true)
|
|
100
115
|
props.onPressIn?.(event)
|
|
101
116
|
}}
|
|
102
117
|
onPressOut={(event) => {
|
|
118
|
+
if (isProcessing) {
|
|
119
|
+
return
|
|
120
|
+
}
|
|
103
121
|
setIsPressed(false)
|
|
104
122
|
props.onPressOut?.(event)
|
|
105
123
|
}}
|
|
@@ -117,7 +135,11 @@ export const IconButton = forwardRef<React.ComponentRef<typeof Pressable>, IconB
|
|
|
117
135
|
<ContentThemeOverrideProvider
|
|
118
136
|
iconStyle={resolvedIconStyle}
|
|
119
137
|
>
|
|
120
|
-
|
|
138
|
+
{isProcessing ? (
|
|
139
|
+
<ThemedLoadingSpinner />
|
|
140
|
+
) : (
|
|
141
|
+
<ThemedIcon icon={icon} />
|
|
142
|
+
)}
|
|
121
143
|
</ContentThemeOverrideProvider>
|
|
122
144
|
</Pressable>
|
|
123
145
|
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Animated,
|
|
4
|
+
Easing
|
|
5
|
+
} from 'react-native'
|
|
6
|
+
import { LoaderCircle } from 'lucide-react-native'
|
|
7
|
+
|
|
8
|
+
import { ThemedIcon, type ThemedIconProps } from './ThemedIcon'
|
|
9
|
+
|
|
10
|
+
export type ThemedLoadingSpinnerProps = Omit<ThemedIconProps, 'icon'>
|
|
11
|
+
|
|
12
|
+
export const ThemedLoadingSpinner = (props: ThemedLoadingSpinnerProps) => {
|
|
13
|
+
const progress = useRef(new Animated.Value(0)).current
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const animation = Animated.loop(
|
|
17
|
+
Animated.timing(progress, {
|
|
18
|
+
toValue: 1,
|
|
19
|
+
duration: 750,
|
|
20
|
+
easing: Easing.linear,
|
|
21
|
+
useNativeDriver: true,
|
|
22
|
+
})
|
|
23
|
+
)
|
|
24
|
+
animation.start()
|
|
25
|
+
return () => {
|
|
26
|
+
animation.stop()
|
|
27
|
+
progress.setValue(0)
|
|
28
|
+
}
|
|
29
|
+
}, [progress])
|
|
30
|
+
|
|
31
|
+
const rotate = progress.interpolate({
|
|
32
|
+
inputRange: [0, 1],
|
|
33
|
+
outputRange: ['0deg', '360deg'],
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Animated.View style={{ transform: [{ rotate }] }}>
|
|
38
|
+
<ThemedIcon icon={LoaderCircle} {...props} />
|
|
39
|
+
</Animated.View>
|
|
40
|
+
)
|
|
41
|
+
}
|