@hero-design/rn 8.58.0 → 8.60.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/es/index.js +185 -104
- package/lib/index.js +185 -104
- package/package.json +1 -1
- package/src/components/AnimatedScroller/AnimatedFAB.tsx +99 -49
- package/src/components/AnimatedScroller/AnimatedScrollable.tsx +18 -3
- package/src/components/AnimatedScroller/__tests__/ScrollablesWithFAB.spec.tsx +30 -9
- package/src/components/AnimatedScroller/__tests__/__snapshots__/ScrollablesWithFAB.spec.tsx.snap +474 -447
- package/src/components/Carousel/CarouselItem.tsx +11 -7
- package/src/components/Carousel/types.ts +1 -1
- package/src/components/FAB/ActionGroup/ActionItem.tsx +3 -1
- package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +216 -211
- package/src/components/FAB/ActionGroup/index.tsx +34 -28
- package/src/components/FAB/FAB.tsx +102 -41
- package/src/components/FAB/StyledFAB.tsx +10 -8
- package/src/components/FAB/__tests__/__snapshots__/StyledFAB.spec.tsx.snap +34 -38
- package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +191 -170
- package/types/components/AnimatedScroller/AnimatedFAB.d.ts +3 -1
- package/types/components/AnimatedScroller/AnimatedScrollable.d.ts +1 -1
- package/types/components/Carousel/types.d.ts +1 -1
- package/types/components/FAB/StyledFAB.d.ts +4 -6
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import Box from '../../Box';
|
|
16
16
|
import { FABHandles } from '../FAB';
|
|
17
17
|
import { useDeprecation } from '../../../utils/hooks';
|
|
18
|
+
import { useTheme } from '../../../theme';
|
|
18
19
|
|
|
19
20
|
export type ActionGroupHandles = {
|
|
20
21
|
showFAB: () => void;
|
|
@@ -88,8 +89,9 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
|
|
|
88
89
|
headerTitle !== undefined
|
|
89
90
|
);
|
|
90
91
|
|
|
92
|
+
const theme = useTheme();
|
|
91
93
|
const fabRef = useRef<FABHandles>(null);
|
|
92
|
-
const
|
|
94
|
+
const animatedValue = useRef<Animated.Value>(
|
|
93
95
|
new Animated.Value(active ? 1 : 0)
|
|
94
96
|
);
|
|
95
97
|
|
|
@@ -104,30 +106,27 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
|
|
|
104
106
|
);
|
|
105
107
|
|
|
106
108
|
React.useEffect(() => {
|
|
107
|
-
Animated.spring(
|
|
109
|
+
Animated.spring(animatedValue.current, {
|
|
108
110
|
toValue: active ? 1 : 0,
|
|
111
|
+
delay: 100,
|
|
109
112
|
useNativeDriver: Platform.OS !== 'web',
|
|
110
113
|
}).start();
|
|
114
|
+
|
|
115
|
+
if (active) {
|
|
116
|
+
fabRef.current?.collapse();
|
|
117
|
+
} else {
|
|
118
|
+
fabRef.current?.show();
|
|
119
|
+
}
|
|
111
120
|
}, [active]);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const interpolatedFABOpacityAnimation =
|
|
119
|
-
tranlateXAnimation.current.interpolate({
|
|
120
|
-
inputRange: [0, 1],
|
|
121
|
-
outputRange: [1, 0],
|
|
122
|
-
});
|
|
121
|
+
|
|
122
|
+
const actionGroupOpacity = animatedValue.current.interpolate({
|
|
123
|
+
inputRange: [0, 1],
|
|
124
|
+
outputRange: [0, 1],
|
|
125
|
+
});
|
|
123
126
|
|
|
124
127
|
return (
|
|
125
128
|
<StyledContainer testID={testID} pointerEvents="box-none" style={style}>
|
|
126
|
-
<Animated.View
|
|
127
|
-
style={{
|
|
128
|
-
opacity: interpolatedFABOpacityAnimation,
|
|
129
|
-
}}
|
|
130
|
-
>
|
|
129
|
+
<Animated.View>
|
|
131
130
|
<StyledFAB
|
|
132
131
|
key="fab"
|
|
133
132
|
testID="fab"
|
|
@@ -151,7 +150,7 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
|
|
|
151
150
|
testID="action-group"
|
|
152
151
|
pointerEvents="box-none"
|
|
153
152
|
style={{
|
|
154
|
-
opacity:
|
|
153
|
+
opacity: actionGroupOpacity,
|
|
155
154
|
}}
|
|
156
155
|
>
|
|
157
156
|
<Box style={[style, { paddingBottom: 0 }]}>
|
|
@@ -166,15 +165,22 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
|
|
|
166
165
|
</Box>
|
|
167
166
|
</StyledActionGroupContainer>
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
168
|
+
{active && (
|
|
169
|
+
<StyledFAB
|
|
170
|
+
// This FAB is moved up a bit compared to the original FAB,
|
|
171
|
+
// set marginBottom to negative value to compensate for it
|
|
172
|
+
style={{
|
|
173
|
+
marginBottom: -theme.space.xxsmall,
|
|
174
|
+
}}
|
|
175
|
+
key="fab-in-portal"
|
|
176
|
+
testID="fab-in-portal"
|
|
177
|
+
icon={fabIcon}
|
|
178
|
+
onPress={onPress}
|
|
179
|
+
animated
|
|
180
|
+
active={active}
|
|
181
|
+
title={fabTitle}
|
|
182
|
+
/>
|
|
183
|
+
)}
|
|
178
184
|
</StyledContainerInModal>
|
|
179
185
|
</Modal>
|
|
180
186
|
</StyledContainer>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import {
|
|
3
|
+
Animated,
|
|
3
4
|
LayoutAnimation,
|
|
4
|
-
LayoutAnimationConfig,
|
|
5
5
|
Platform,
|
|
6
6
|
StyleProp,
|
|
7
7
|
StyleSheet,
|
|
@@ -18,18 +18,18 @@ import {
|
|
|
18
18
|
StyledIconContainer,
|
|
19
19
|
} from './StyledFAB';
|
|
20
20
|
|
|
21
|
-
if (Platform.OS === 'android') {
|
|
22
|
-
if (UIManager.setLayoutAnimationEnabledExperimental) {
|
|
23
|
-
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
21
|
export type FABHandles = {
|
|
28
22
|
show: () => void;
|
|
29
23
|
collapse: () => void;
|
|
30
24
|
hide: () => void;
|
|
31
25
|
};
|
|
32
26
|
|
|
27
|
+
if (Platform.OS === 'android') {
|
|
28
|
+
if (UIManager.setLayoutAnimationEnabledExperimental) {
|
|
29
|
+
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
33
|
export interface FABProps {
|
|
34
34
|
/**
|
|
35
35
|
* Name of the Icon.
|
|
@@ -105,65 +105,104 @@ const IconWithTextContent = ({
|
|
|
105
105
|
</>
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
},
|
|
117
|
-
duration: Platform.OS === 'ios' ? 300 : 400,
|
|
108
|
+
const animateWidth = () => {
|
|
109
|
+
LayoutAnimation.configureNext({
|
|
110
|
+
duration: Platform.OS === 'ios' ? 200 : 400,
|
|
111
|
+
update: {
|
|
112
|
+
type: 'spring',
|
|
113
|
+
springDamping: Platform.OS === 'ios' ? 1 : 1.5,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
118
116
|
};
|
|
119
117
|
|
|
120
118
|
const FAB = forwardRef<FABHandles, FABProps>(
|
|
121
119
|
({ onPress, title, icon, animated, testID, active, style }, ref) => {
|
|
122
120
|
const theme = useTheme();
|
|
123
|
-
const [canAnimate, setCanAnimate] = React.useState(false);
|
|
124
121
|
const [displayState, setDisplayState] = React.useState({
|
|
125
122
|
hideTitle: false,
|
|
126
123
|
hideButton: false,
|
|
127
124
|
});
|
|
128
125
|
const isIconOnly = displayState.hideTitle || active || !title;
|
|
129
126
|
|
|
127
|
+
const animatedValues = {
|
|
128
|
+
opacity: React.useRef(new Animated.Value(1)).current,
|
|
129
|
+
width: React.useRef(new Animated.Value(1)).current,
|
|
130
|
+
translateY: React.useRef(new Animated.Value(0)).current,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const marginBottom = Number(StyleSheet.flatten(style)?.marginBottom) || 0;
|
|
134
|
+
const [buttonWidth, setButtonWidth] = React.useState(0);
|
|
135
|
+
const hasSetButtonWidth = buttonWidth > 0;
|
|
136
|
+
|
|
130
137
|
React.useImperativeHandle(
|
|
131
138
|
ref,
|
|
132
139
|
() => ({
|
|
133
140
|
show: () => {
|
|
141
|
+
Animated.spring(animatedValues.translateY, {
|
|
142
|
+
toValue: 0,
|
|
143
|
+
useNativeDriver: true,
|
|
144
|
+
}).start();
|
|
145
|
+
|
|
134
146
|
setDisplayState({
|
|
135
147
|
hideButton: false,
|
|
136
148
|
hideTitle: false,
|
|
137
149
|
});
|
|
150
|
+
|
|
151
|
+
animateWidth();
|
|
152
|
+
|
|
153
|
+
Animated.spring(animatedValues.opacity, {
|
|
154
|
+
toValue: 1,
|
|
155
|
+
useNativeDriver: true,
|
|
156
|
+
}).start();
|
|
138
157
|
},
|
|
139
158
|
collapse: () => {
|
|
159
|
+
Animated.parallel([
|
|
160
|
+
Animated.spring(animatedValues.opacity, {
|
|
161
|
+
toValue: 1,
|
|
162
|
+
useNativeDriver: true,
|
|
163
|
+
}),
|
|
164
|
+
Animated.spring(animatedValues.translateY, {
|
|
165
|
+
toValue: 0,
|
|
166
|
+
useNativeDriver: true,
|
|
167
|
+
}),
|
|
168
|
+
]).start();
|
|
169
|
+
|
|
170
|
+
animateWidth();
|
|
171
|
+
|
|
140
172
|
setDisplayState({
|
|
141
173
|
hideButton: false,
|
|
142
174
|
hideTitle: true,
|
|
143
175
|
});
|
|
144
176
|
},
|
|
145
177
|
hide: () => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
178
|
+
Animated.stagger(20, [
|
|
179
|
+
Animated.spring(animatedValues.opacity, {
|
|
180
|
+
toValue: 0,
|
|
181
|
+
useNativeDriver: true,
|
|
182
|
+
}),
|
|
183
|
+
Animated.spring(animatedValues.translateY, {
|
|
184
|
+
toValue: 1,
|
|
185
|
+
useNativeDriver: true,
|
|
186
|
+
}),
|
|
187
|
+
]).start(() => {
|
|
188
|
+
animateWidth();
|
|
189
|
+
setDisplayState((previousState) => ({
|
|
190
|
+
...previousState,
|
|
191
|
+
hideButton: true,
|
|
192
|
+
}));
|
|
193
|
+
});
|
|
150
194
|
},
|
|
151
195
|
}),
|
|
152
196
|
[]
|
|
153
197
|
);
|
|
154
198
|
|
|
155
|
-
React.useEffect(() => {
|
|
156
|
-
if (canAnimate) {
|
|
157
|
-
LayoutAnimation.configureNext(defaultAnimation);
|
|
158
|
-
}
|
|
159
|
-
}, [isIconOnly, displayState.hideButton, canAnimate]);
|
|
160
|
-
|
|
161
|
-
const marginBottom = Number(StyleSheet.flatten(style)?.marginBottom) || 0;
|
|
162
|
-
|
|
163
199
|
return (
|
|
164
200
|
<StyledFAB
|
|
165
|
-
|
|
166
|
-
|
|
201
|
+
onLayout={(event) =>
|
|
202
|
+
!hasSetButtonWidth &&
|
|
203
|
+
!active &&
|
|
204
|
+
setButtonWidth(event.nativeEvent.layout.width)
|
|
205
|
+
}
|
|
167
206
|
underlayColor={theme.__hd__.fab.colors.buttonPressedBackground}
|
|
168
207
|
onPress={onPress}
|
|
169
208
|
style={[
|
|
@@ -172,20 +211,42 @@ const FAB = forwardRef<FABHandles, FABProps>(
|
|
|
172
211
|
bottom: displayState.hideButton
|
|
173
212
|
? -(marginBottom + theme.__hd__.fab.sizes.height * 2)
|
|
174
213
|
: StyleSheet.flatten(style)?.bottom,
|
|
214
|
+
|
|
215
|
+
transform: [
|
|
216
|
+
{
|
|
217
|
+
translateY: animatedValues.translateY.interpolate({
|
|
218
|
+
inputRange: [0, 1],
|
|
219
|
+
outputRange: [
|
|
220
|
+
0,
|
|
221
|
+
marginBottom + theme.__hd__.fab.sizes.height * 2,
|
|
222
|
+
],
|
|
223
|
+
}),
|
|
224
|
+
},
|
|
225
|
+
],
|
|
175
226
|
},
|
|
176
227
|
]}
|
|
177
228
|
testID={testID}
|
|
178
229
|
themeActive={active}
|
|
179
230
|
>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
231
|
+
<Animated.View
|
|
232
|
+
style={{
|
|
233
|
+
flexDirection: 'row',
|
|
234
|
+
opacity: animatedValues.opacity.interpolate({
|
|
235
|
+
inputRange: [0, 1],
|
|
236
|
+
outputRange: [0, 1],
|
|
237
|
+
}),
|
|
238
|
+
}}
|
|
239
|
+
>
|
|
240
|
+
{isIconOnly ? (
|
|
241
|
+
<IconOnlyContent
|
|
242
|
+
animated={animated}
|
|
243
|
+
active={active}
|
|
244
|
+
icon={active ? 'add' : icon}
|
|
245
|
+
/>
|
|
246
|
+
) : (
|
|
247
|
+
<IconWithTextContent icon={icon} title={title} />
|
|
248
|
+
)}
|
|
249
|
+
</Animated.View>
|
|
189
250
|
</StyledFAB>
|
|
190
251
|
);
|
|
191
252
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import styled from '@emotion/native';
|
|
2
|
-
import type { TextProps
|
|
3
|
-
import { TouchableHighlight } from 'react-native';
|
|
2
|
+
import type { TextProps } from 'react-native';
|
|
3
|
+
import { Animated, TouchableHighlight } from 'react-native';
|
|
4
|
+
import Box from '../Box';
|
|
4
5
|
import type { IconProps } from '../Icon';
|
|
5
6
|
import Icon from '../Icon';
|
|
6
7
|
import Typography from '../Typography';
|
|
7
|
-
import Box from '../Box';
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const AnimatedTouchableHighlight =
|
|
10
|
+
Animated.createAnimatedComponent(TouchableHighlight);
|
|
11
|
+
|
|
12
|
+
const StyledFAB = styled(AnimatedTouchableHighlight)<{
|
|
13
|
+
themeActive?: boolean;
|
|
14
|
+
}>(({ theme, themeActive }) => ({
|
|
14
15
|
backgroundColor: themeActive
|
|
15
16
|
? theme.__hd__.fab.colors.buttonActiveBackground
|
|
16
17
|
: theme.__hd__.fab.colors.buttonBackground,
|
|
@@ -25,6 +26,7 @@ const StyledFAB = styled(TouchableHighlight)<
|
|
|
25
26
|
shadowOffset: theme.__hd__.fab.shadows.offset,
|
|
26
27
|
shadowRadius: theme.__hd__.fab.shadows.radius,
|
|
27
28
|
shadowOpacity: theme.__hd__.fab.shadows.opacity,
|
|
29
|
+
height: theme.__hd__.fab.sizes.height,
|
|
28
30
|
}));
|
|
29
31
|
|
|
30
32
|
const StyledFABIcon = styled(Icon)<IconProps>(({ theme }) => ({
|
|
@@ -27,26 +27,24 @@ exports[`StyledFAB renders correctly 1`] = `
|
|
|
27
27
|
onResponderTerminationRequest={[Function]}
|
|
28
28
|
onStartShouldSetResponder={[Function]}
|
|
29
29
|
style={
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
"shadowOpacity": 0.12,
|
|
46
|
-
"shadowRadius": 4,
|
|
30
|
+
{
|
|
31
|
+
"alignItems": "center",
|
|
32
|
+
"alignSelf": "flex-start",
|
|
33
|
+
"backgroundColor": "#401960",
|
|
34
|
+
"borderRadius": 999,
|
|
35
|
+
"elevation": 3,
|
|
36
|
+
"flexDirection": "row",
|
|
37
|
+
"height": 64,
|
|
38
|
+
"justifyContent": "center",
|
|
39
|
+
"padding": 20,
|
|
40
|
+
"shadowColor": "#001f23",
|
|
41
|
+
"shadowOffset": {
|
|
42
|
+
"height": 2,
|
|
43
|
+
"width": 0,
|
|
47
44
|
},
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
"shadowOpacity": 0.12,
|
|
46
|
+
"shadowRadius": 4,
|
|
47
|
+
}
|
|
50
48
|
}
|
|
51
49
|
>
|
|
52
50
|
<Text
|
|
@@ -120,26 +118,24 @@ exports[`StyledFAB renders correctly 2`] = `
|
|
|
120
118
|
onResponderTerminationRequest={[Function]}
|
|
121
119
|
onStartShouldSetResponder={[Function]}
|
|
122
120
|
style={
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
},
|
|
138
|
-
"shadowOpacity": 0.12,
|
|
139
|
-
"shadowRadius": 4,
|
|
121
|
+
{
|
|
122
|
+
"alignItems": "center",
|
|
123
|
+
"alignSelf": "flex-start",
|
|
124
|
+
"backgroundColor": "#33144d",
|
|
125
|
+
"borderRadius": 999,
|
|
126
|
+
"elevation": 3,
|
|
127
|
+
"flexDirection": "row",
|
|
128
|
+
"height": 64,
|
|
129
|
+
"justifyContent": "center",
|
|
130
|
+
"padding": 20,
|
|
131
|
+
"shadowColor": "#001f23",
|
|
132
|
+
"shadowOffset": {
|
|
133
|
+
"height": 2,
|
|
134
|
+
"width": 0,
|
|
140
135
|
},
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
"shadowOpacity": 0.12,
|
|
137
|
+
"shadowRadius": 4,
|
|
138
|
+
}
|
|
143
139
|
}
|
|
144
140
|
>
|
|
145
141
|
<Text
|