@hero-design/rn 8.59.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 +6 -0
- package/es/index.js +183 -102
- package/lib/index.js +183 -102
- 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/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/FAB/StyledFAB.d.ts +4 -6
|
@@ -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
|