@hero-design/rn 8.32.1 → 8.33.1
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/es/index.js +163 -54
- package/lib/index.js +163 -54
- package/package.json +5 -5
- package/src/components/Button/LoadingIndicator/StyledLoadingIndicator.tsx +2 -1
- package/src/components/Button/LoadingIndicator/__tests__/__snapshots__/index.spec.tsx.snap +10 -10
- package/src/components/Button/__tests__/__snapshots__/Button.spec.tsx.snap +6 -6
- package/src/components/FAB/ActionGroup/ActionItem.tsx +44 -15
- package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +982 -819
- package/src/components/FAB/ActionGroup/__tests__/index.spec.tsx +4 -11
- package/src/components/FAB/ActionGroup/index.tsx +119 -93
- package/src/components/FAB/AnimatedFABIcon.tsx +3 -5
- package/src/components/FAB/FAB.tsx +108 -28
- package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +27 -9
- package/src/components/FAB/__tests__/index.spec.tsx +22 -2
- package/src/components/Typography/Text/index.tsx +19 -12
- package/src/components/Typography/index.tsx +3 -0
- package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +1 -0
- package/src/theme/components/button.ts +1 -0
- package/src/types.ts +4 -0
- package/testUtils/setup.tsx +2 -0
- package/types/components/FAB/ActionGroup/ActionItem.d.ts +6 -2
- package/types/components/FAB/ActionGroup/StyledActionGroup.d.ts +1 -1
- package/types/components/FAB/ActionGroup/index.d.ts +7 -1
- package/types/components/FAB/FAB.d.ts +8 -2
- package/types/components/FAB/index.d.ts +3 -2
- package/types/components/Typography/index.d.ts +3 -0
- package/types/theme/components/button.d.ts +1 -0
- package/types/types.d.ts +3 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import '@testing-library/jest-native/extend-expect';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
import { fireEvent } from '@testing-library/react-native';
|
|
4
|
-
import
|
|
3
|
+
import React from 'react';
|
|
5
4
|
import ActionGroup from '..';
|
|
5
|
+
import renderWithTheme from '../../../../testHelpers/renderWithTheme';
|
|
6
6
|
|
|
7
7
|
describe('ActionGroup', () => {
|
|
8
8
|
it.each`
|
|
@@ -40,23 +40,16 @@ describe('ActionGroup', () => {
|
|
|
40
40
|
expect(toJSON()).toMatchSnapshot();
|
|
41
41
|
|
|
42
42
|
expect(getByText('What would you like to create?')).toBeDefined();
|
|
43
|
-
expect(getByText('Shout out')).toBeDefined();
|
|
44
43
|
expect(getByTestId('speaker-action-item')).toBeDefined();
|
|
45
44
|
expect(getByTestId('target-action-item')).toBeDefined();
|
|
46
45
|
expect(getByTestId('plane-action-item')).toBeDefined();
|
|
47
46
|
expect(getByTestId('health-bag-action-item')).toBeDefined();
|
|
48
47
|
|
|
49
48
|
if (active) {
|
|
50
|
-
// verify
|
|
51
|
-
expect(getByTestId('action-group')).toHaveStyle({
|
|
52
|
-
transform: [{ translateX: 0 }],
|
|
53
|
-
});
|
|
49
|
+
// verify backdrop appears
|
|
54
50
|
expect(getByTestId('back-drop')).toHaveProp('pointerEvents', 'auto');
|
|
55
51
|
} else {
|
|
56
|
-
// verify
|
|
57
|
-
expect(getByTestId('action-group')).toHaveStyle({
|
|
58
|
-
transform: [{ translateX: 400 }],
|
|
59
|
-
});
|
|
52
|
+
// verify backdrop disappears
|
|
60
53
|
expect(getByTestId('back-drop')).toHaveProp('pointerEvents', 'box-none');
|
|
61
54
|
}
|
|
62
55
|
});
|
|
@@ -1,35 +1,24 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import { Animated, Easing, Platform, View } from 'react-native';
|
|
1
|
+
import React, { forwardRef, useRef } from 'react';
|
|
3
2
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { Animated, Platform } from 'react-native';
|
|
4
|
+
import type { IconName } from '../../Icon';
|
|
5
|
+
import type { ActionItemProps } from './ActionItem';
|
|
4
6
|
import ActionItem from './ActionItem';
|
|
5
7
|
import {
|
|
8
|
+
StyledActionGroupContainer,
|
|
6
9
|
StyledBackdrop,
|
|
7
10
|
StyledContainer,
|
|
8
11
|
StyledFAB,
|
|
9
12
|
StyledHeaderText,
|
|
10
|
-
StyledActionGroupContainer,
|
|
11
13
|
} from './StyledActionGroup';
|
|
12
|
-
import type { IconName } from '../../Icon';
|
|
13
|
-
import type { ActionItemProps } from './ActionItem';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}: ActionItemsContainerProps) => {
|
|
23
|
-
return (
|
|
24
|
-
<View style={style}>
|
|
25
|
-
{items?.map((itemProp) => (
|
|
26
|
-
<ActionItem
|
|
27
|
-
key={itemProp.key || `${itemProp.icon}_${itemProp.title}`}
|
|
28
|
-
{...itemProp}
|
|
29
|
-
/>
|
|
30
|
-
))}
|
|
31
|
-
</View>
|
|
32
|
-
);
|
|
15
|
+
import Box from '../../Box';
|
|
16
|
+
import { FABHandles } from '../FAB';
|
|
17
|
+
|
|
18
|
+
export type ActionGroupHandles = {
|
|
19
|
+
showFAB: () => void;
|
|
20
|
+
collapseFAB: () => void;
|
|
21
|
+
hideFAB: () => void;
|
|
33
22
|
};
|
|
34
23
|
|
|
35
24
|
export interface ActionGroupProps {
|
|
@@ -66,87 +55,124 @@ export interface ActionGroupProps {
|
|
|
66
55
|
/**
|
|
67
56
|
* Action items of the action group.
|
|
68
57
|
* */
|
|
69
|
-
|
|
70
58
|
items?: Array<ActionItemProps>;
|
|
59
|
+
|
|
71
60
|
/**
|
|
72
61
|
* Testing id of the component.
|
|
73
62
|
*/
|
|
74
|
-
|
|
75
63
|
testID?: string;
|
|
76
64
|
}
|
|
77
|
-
const ActionGroup = ({
|
|
78
|
-
headerTitle,
|
|
79
|
-
onPress,
|
|
80
|
-
active,
|
|
81
|
-
style,
|
|
82
|
-
items,
|
|
83
|
-
testID,
|
|
84
|
-
fabTitle,
|
|
85
|
-
fabIcon = 'add',
|
|
86
|
-
}: ActionGroupProps) => {
|
|
87
|
-
const tranlateXAnimation = useRef<Animated.Value>(
|
|
88
|
-
new Animated.Value(active ? 1 : 0)
|
|
89
|
-
);
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
const animation = Animated.timing(tranlateXAnimation.current, {
|
|
92
|
-
toValue: active ? 1 : 0,
|
|
93
|
-
useNativeDriver: Platform.OS === 'ios' || Platform.OS === 'android',
|
|
94
|
-
easing: Easing.inOut(Easing.cubic),
|
|
95
|
-
});
|
|
96
65
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const interpolatedTranlateXAnimation = tranlateXAnimation.current.interpolate(
|
|
66
|
+
const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
|
|
67
|
+
(
|
|
101
68
|
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
69
|
+
headerTitle,
|
|
70
|
+
onPress,
|
|
71
|
+
active,
|
|
72
|
+
style,
|
|
73
|
+
items,
|
|
74
|
+
testID,
|
|
75
|
+
fabTitle,
|
|
76
|
+
fabIcon = 'add',
|
|
77
|
+
},
|
|
78
|
+
ref
|
|
79
|
+
) => {
|
|
80
|
+
const fabRef = useRef<FABHandles>(null);
|
|
81
|
+
const tranlateXAnimation = useRef<Animated.Value>(
|
|
82
|
+
new Animated.Value(active ? 1 : 0)
|
|
83
|
+
);
|
|
84
|
+
const titleTranslateYValue = React.useRef(new Animated.Value(0));
|
|
111
85
|
|
|
112
|
-
|
|
113
|
-
tranlateXAnimation.current.interpolate({
|
|
86
|
+
const titleTranslateY = titleTranslateYValue.current.interpolate({
|
|
114
87
|
inputRange: [0, 1],
|
|
115
|
-
outputRange: [
|
|
88
|
+
outputRange: [50, 0],
|
|
116
89
|
});
|
|
117
90
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
91
|
+
React.useImperativeHandle(
|
|
92
|
+
ref,
|
|
93
|
+
() => ({
|
|
94
|
+
showFAB: () => fabRef.current?.show(),
|
|
95
|
+
collapseFAB: () => fabRef.current?.collapse(),
|
|
96
|
+
hideFAB: () => fabRef.current?.hide(),
|
|
97
|
+
}),
|
|
98
|
+
[fabRef]
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
React.useEffect(() => {
|
|
102
|
+
Animated.parallel([
|
|
103
|
+
Animated.spring(tranlateXAnimation.current, {
|
|
104
|
+
toValue: active ? 1 : 0,
|
|
105
|
+
useNativeDriver: Platform.OS !== 'web',
|
|
106
|
+
}),
|
|
107
|
+
Animated.spring(titleTranslateYValue.current, {
|
|
108
|
+
toValue: active ? 1 : 0,
|
|
109
|
+
useNativeDriver: Platform.OS !== 'web',
|
|
110
|
+
}),
|
|
111
|
+
]).start();
|
|
112
|
+
}, [active]);
|
|
113
|
+
|
|
114
|
+
const interpolatedBackdropOpacityAnimation =
|
|
115
|
+
tranlateXAnimation.current.interpolate({
|
|
116
|
+
inputRange: [0, 1],
|
|
117
|
+
outputRange: [0, 0.4],
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const interpolatedActionGroupOpacityAnimation =
|
|
121
|
+
tranlateXAnimation.current.interpolate({
|
|
122
|
+
inputRange: [0, 1],
|
|
123
|
+
outputRange: [0, 1],
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<StyledContainer testID={testID} pointerEvents="box-none" style={style}>
|
|
128
|
+
<StyledBackdrop
|
|
129
|
+
pointerEvents={active ? 'auto' : 'box-none'}
|
|
130
|
+
testID="back-drop"
|
|
131
|
+
style={{ opacity: interpolatedBackdropOpacityAnimation }}
|
|
132
|
+
/>
|
|
133
|
+
<StyledActionGroupContainer
|
|
134
|
+
pointerEvents={active ? 'auto' : 'none'}
|
|
135
|
+
testID="action-group"
|
|
136
|
+
style={{
|
|
137
|
+
opacity: interpolatedActionGroupOpacityAnimation,
|
|
138
|
+
}}
|
|
139
|
+
>
|
|
140
|
+
{!!headerTitle && (
|
|
141
|
+
<Animated.View
|
|
142
|
+
style={{ transform: [{ translateY: titleTranslateY }] }}
|
|
143
|
+
>
|
|
144
|
+
<StyledHeaderText testID="header-text">
|
|
145
|
+
{headerTitle}
|
|
146
|
+
</StyledHeaderText>
|
|
147
|
+
</Animated.View>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
<Box style={[style, { paddingBottom: 0 }]}>
|
|
151
|
+
{items?.map((itemProp, index) => (
|
|
152
|
+
<ActionItem
|
|
153
|
+
key={itemProp.key || `${itemProp.icon}_${itemProp.title}`}
|
|
154
|
+
{...itemProp}
|
|
155
|
+
index={active ? index : items.length - index}
|
|
156
|
+
active={active}
|
|
157
|
+
/>
|
|
158
|
+
))}
|
|
159
|
+
</Box>
|
|
160
|
+
</StyledActionGroupContainer>
|
|
161
|
+
|
|
162
|
+
<StyledFAB
|
|
163
|
+
testID="fab"
|
|
164
|
+
icon={fabIcon}
|
|
165
|
+
onPress={onPress}
|
|
166
|
+
animated
|
|
167
|
+
active={active}
|
|
168
|
+
title={fabTitle}
|
|
169
|
+
ref={fabRef}
|
|
170
|
+
/>
|
|
171
|
+
</StyledContainer>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
ActionGroup.displayName = 'FAB.ActionGroup';
|
|
151
177
|
|
|
152
178
|
export default ActionGroup;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { Animated,
|
|
3
|
-
import { StyledFABIcon } from './StyledFAB';
|
|
2
|
+
import { Animated, Platform, StyleSheet } from 'react-native';
|
|
4
3
|
import type { IconProps } from '../Icon';
|
|
4
|
+
import { StyledFABIcon } from './StyledFAB';
|
|
5
5
|
|
|
6
6
|
const AnimatedIcons = Animated.createAnimatedComponent(StyledFABIcon);
|
|
7
7
|
|
|
@@ -14,11 +14,9 @@ const AnimatedFABIcon = ({ active, ...iconProps }: Props) => {
|
|
|
14
14
|
new Animated.Value(active ? 1 : 0)
|
|
15
15
|
);
|
|
16
16
|
useEffect(() => {
|
|
17
|
-
const animation = Animated.
|
|
17
|
+
const animation = Animated.spring(rotateAnimation.current, {
|
|
18
18
|
toValue: active ? 1 : 0,
|
|
19
19
|
useNativeDriver: Platform.OS === 'ios' || Platform.OS === 'android',
|
|
20
|
-
easing: Easing.inOut(Easing.ease),
|
|
21
|
-
duration: 300,
|
|
22
20
|
});
|
|
23
21
|
|
|
24
22
|
animation.start();
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
LayoutAnimation,
|
|
4
|
+
LayoutAnimationConfig,
|
|
5
|
+
Platform,
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
UIManager,
|
|
9
|
+
ViewStyle,
|
|
10
|
+
} from 'react-native';
|
|
3
11
|
import { useTheme } from '../../theme';
|
|
4
12
|
import type { IconName } from '../Icon';
|
|
5
13
|
import { AnimatedFABIcon } from './AnimatedFABIcon';
|
|
@@ -10,6 +18,18 @@ import {
|
|
|
10
18
|
StyledIconContainer,
|
|
11
19
|
} from './StyledFAB';
|
|
12
20
|
|
|
21
|
+
if (Platform.OS === 'android') {
|
|
22
|
+
if (UIManager.setLayoutAnimationEnabledExperimental) {
|
|
23
|
+
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type FABHandles = {
|
|
28
|
+
show: () => void;
|
|
29
|
+
collapse: () => void;
|
|
30
|
+
hide: () => void;
|
|
31
|
+
};
|
|
32
|
+
|
|
13
33
|
export interface FABProps {
|
|
14
34
|
/**
|
|
15
35
|
* Name of the Icon.
|
|
@@ -54,7 +74,6 @@ const IconOnlyContent = ({
|
|
|
54
74
|
}: {
|
|
55
75
|
icon: IconName;
|
|
56
76
|
animated?: boolean;
|
|
57
|
-
|
|
58
77
|
active?: boolean;
|
|
59
78
|
}) => {
|
|
60
79
|
if (animated) {
|
|
@@ -85,31 +104,92 @@ const IconWithTextContent = ({
|
|
|
85
104
|
<StyledFABText>{title}</StyledFABText>
|
|
86
105
|
</>
|
|
87
106
|
);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}: FABProps): JSX.Element => {
|
|
97
|
-
const isIconOnly = !title;
|
|
98
|
-
const theme = useTheme();
|
|
99
|
-
return (
|
|
100
|
-
<StyledFAB
|
|
101
|
-
underlayColor={theme.__hd__.fab.colors.buttonPressedBackground}
|
|
102
|
-
onPress={onPress}
|
|
103
|
-
style={style}
|
|
104
|
-
testID={testID}
|
|
105
|
-
>
|
|
106
|
-
{isIconOnly ? (
|
|
107
|
-
<IconOnlyContent animated={animated} active={active} icon={icon} />
|
|
108
|
-
) : (
|
|
109
|
-
<IconWithTextContent icon={icon} title={title} />
|
|
110
|
-
)}
|
|
111
|
-
</StyledFAB>
|
|
112
|
-
);
|
|
107
|
+
|
|
108
|
+
const defaultAnimation: LayoutAnimationConfig = {
|
|
109
|
+
create: {
|
|
110
|
+
type: 'easeInEaseOut',
|
|
111
|
+
property: 'opacity',
|
|
112
|
+
},
|
|
113
|
+
update: { type: 'spring', springDamping: Platform.OS === 'ios' ? 0.7 : 1 },
|
|
114
|
+
duration: 400,
|
|
113
115
|
};
|
|
114
116
|
|
|
117
|
+
const FAB = forwardRef<FABHandles, FABProps>(
|
|
118
|
+
({ onPress, title, icon, animated, testID, active, style }, ref) => {
|
|
119
|
+
const theme = useTheme();
|
|
120
|
+
|
|
121
|
+
const [displayState, setDisplayState] = React.useState({
|
|
122
|
+
hideTitle: false,
|
|
123
|
+
hideButton: false,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const [canAnimate, setCanAnimate] = React.useState(false);
|
|
127
|
+
|
|
128
|
+
const isIconOnly = displayState.hideTitle || active || !title;
|
|
129
|
+
|
|
130
|
+
React.useImperativeHandle(
|
|
131
|
+
ref,
|
|
132
|
+
() => ({
|
|
133
|
+
show: () => {
|
|
134
|
+
setDisplayState({
|
|
135
|
+
hideButton: false,
|
|
136
|
+
hideTitle: false,
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
collapse: () => {
|
|
140
|
+
setDisplayState({
|
|
141
|
+
hideButton: false,
|
|
142
|
+
hideTitle: true,
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
hide: () => {
|
|
146
|
+
setDisplayState((previousState) => ({
|
|
147
|
+
...previousState,
|
|
148
|
+
hideButton: true,
|
|
149
|
+
}));
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
[]
|
|
153
|
+
);
|
|
154
|
+
|
|
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
|
+
return (
|
|
164
|
+
<StyledFAB
|
|
165
|
+
/** Add a small timeout before executing animation to prevent flakiness */
|
|
166
|
+
onLayout={() => setTimeout(() => setCanAnimate(true), 500)}
|
|
167
|
+
underlayColor={theme.__hd__.fab.colors.buttonPressedBackground}
|
|
168
|
+
onPress={onPress}
|
|
169
|
+
style={[
|
|
170
|
+
style,
|
|
171
|
+
{
|
|
172
|
+
bottom: displayState.hideButton
|
|
173
|
+
? -(marginBottom + theme.__hd__.fab.sizes.height * 2)
|
|
174
|
+
: StyleSheet.flatten(style)?.bottom,
|
|
175
|
+
},
|
|
176
|
+
]}
|
|
177
|
+
testID={testID}
|
|
178
|
+
>
|
|
179
|
+
{isIconOnly ? (
|
|
180
|
+
<IconOnlyContent
|
|
181
|
+
animated={animated}
|
|
182
|
+
active={active}
|
|
183
|
+
icon={active ? 'add' : icon}
|
|
184
|
+
/>
|
|
185
|
+
) : (
|
|
186
|
+
<IconWithTextContent icon={icon} title={title} />
|
|
187
|
+
)}
|
|
188
|
+
</StyledFAB>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
FAB.displayName = 'FAB';
|
|
194
|
+
|
|
115
195
|
export default FAB;
|
|
@@ -5,6 +5,7 @@ exports[`FAB when animated is false renders StyledFABIcon 1`] = `
|
|
|
5
5
|
accessible={true}
|
|
6
6
|
focusable={false}
|
|
7
7
|
onClick={[Function]}
|
|
8
|
+
onLayout={[Function]}
|
|
8
9
|
onResponderGrant={[Function]}
|
|
9
10
|
onResponderMove={[Function]}
|
|
10
11
|
onResponderRelease={[Function]}
|
|
@@ -30,9 +31,14 @@ exports[`FAB when animated is false renders StyledFABIcon 1`] = `
|
|
|
30
31
|
"shadowOpacity": 0.12,
|
|
31
32
|
"shadowRadius": 8,
|
|
32
33
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
Array [
|
|
35
|
+
Object {
|
|
36
|
+
"backgroundColor": "#001f23",
|
|
37
|
+
},
|
|
38
|
+
Object {
|
|
39
|
+
"bottom": undefined,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
36
42
|
]
|
|
37
43
|
}
|
|
38
44
|
>
|
|
@@ -67,6 +73,7 @@ exports[`FAB when animated is true renders animatedFABIcon 1`] = `
|
|
|
67
73
|
accessible={true}
|
|
68
74
|
focusable={false}
|
|
69
75
|
onClick={[Function]}
|
|
76
|
+
onLayout={[Function]}
|
|
70
77
|
onResponderGrant={[Function]}
|
|
71
78
|
onResponderMove={[Function]}
|
|
72
79
|
onResponderRelease={[Function]}
|
|
@@ -92,9 +99,14 @@ exports[`FAB when animated is true renders animatedFABIcon 1`] = `
|
|
|
92
99
|
"shadowOpacity": 0.12,
|
|
93
100
|
"shadowRadius": 8,
|
|
94
101
|
},
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
102
|
+
Array [
|
|
103
|
+
Object {
|
|
104
|
+
"backgroundColor": "#001f23",
|
|
105
|
+
},
|
|
106
|
+
Object {
|
|
107
|
+
"bottom": undefined,
|
|
108
|
+
},
|
|
109
|
+
],
|
|
98
110
|
]
|
|
99
111
|
}
|
|
100
112
|
>
|
|
@@ -159,6 +171,7 @@ exports[`FAB when title has value renders correctly 1`] = `
|
|
|
159
171
|
accessible={true}
|
|
160
172
|
focusable={false}
|
|
161
173
|
onClick={[Function]}
|
|
174
|
+
onLayout={[Function]}
|
|
162
175
|
onResponderGrant={[Function]}
|
|
163
176
|
onResponderMove={[Function]}
|
|
164
177
|
onResponderRelease={[Function]}
|
|
@@ -184,9 +197,14 @@ exports[`FAB when title has value renders correctly 1`] = `
|
|
|
184
197
|
"shadowOpacity": 0.12,
|
|
185
198
|
"shadowRadius": 8,
|
|
186
199
|
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
200
|
+
Array [
|
|
201
|
+
Object {
|
|
202
|
+
"backgroundColor": "#001f23",
|
|
203
|
+
},
|
|
204
|
+
Object {
|
|
205
|
+
"bottom": undefined,
|
|
206
|
+
},
|
|
207
|
+
],
|
|
190
208
|
]
|
|
191
209
|
}
|
|
192
210
|
>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { createRef } from 'react';
|
|
2
2
|
import { fireEvent } from '@testing-library/react-native';
|
|
3
3
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
4
|
-
import { theme } from '../../../index';
|
|
4
|
+
import { FABHandles, theme } from '../../../index';
|
|
5
5
|
import FAB from '..';
|
|
6
6
|
|
|
7
7
|
describe('FAB', () => {
|
|
@@ -66,4 +66,24 @@ describe('FAB', () => {
|
|
|
66
66
|
expect(onPressSpy).toBeCalledTimes(1);
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
|
+
|
|
70
|
+
describe('usage with ref', () => {
|
|
71
|
+
it('allow controlling inner fab states by ref', () => {
|
|
72
|
+
const fabRef = createRef<FABHandles>();
|
|
73
|
+
|
|
74
|
+
const { queryByText } = renderWithTheme(
|
|
75
|
+
<FAB ref={fabRef} title="Shout out" icon="speaker" />
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(queryByText('Shout out')).toBeDefined();
|
|
79
|
+
fabRef.current!.collapse();
|
|
80
|
+
expect(queryByText('Shout out')).toBeFalsy();
|
|
81
|
+
|
|
82
|
+
fabRef.current!.show();
|
|
83
|
+
expect(queryByText('Shout out')).toBeDefined();
|
|
84
|
+
|
|
85
|
+
fabRef.current!.hide();
|
|
86
|
+
expect(queryByText('Shout out')).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
69
89
|
});
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
TextStyle,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
import { StyledText } from './StyledText';
|
|
9
|
+
import { useDeprecation } from '../../../utils/hooks';
|
|
9
10
|
|
|
10
11
|
export interface TextProps extends NativeTextProps {
|
|
11
12
|
/**
|
|
@@ -69,17 +70,23 @@ const Text = ({
|
|
|
69
70
|
typeface = 'neutral',
|
|
70
71
|
allowFontScaling = false,
|
|
71
72
|
...nativeProps
|
|
72
|
-
}: TextProps) =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
}: TextProps) => {
|
|
74
|
+
useDeprecation(
|
|
75
|
+
'Typography.Text is deprecated and will be removed in the next major release, please refer to https://design.employmenthero.com/mobile/Components/typography for the appropriate alternatives.'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<StyledText
|
|
80
|
+
{...nativeProps}
|
|
81
|
+
themeFontSize={fontSize}
|
|
82
|
+
themeFontWeight={fontWeight}
|
|
83
|
+
themeIntent={intent}
|
|
84
|
+
themeTypeface={typeface}
|
|
85
|
+
allowFontScaling={allowFontScaling}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</StyledText>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
84
91
|
|
|
85
92
|
export default Text;
|
|
@@ -5,6 +5,9 @@ import Title from './Title';
|
|
|
5
5
|
import Body from './Body';
|
|
6
6
|
|
|
7
7
|
interface TypographyProps {
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Typography.Text will be removed in the next major release, please refer to https://design.employmenthero.com/mobile/Components/typography for the appropriate alternatives.
|
|
10
|
+
*/
|
|
8
11
|
Text: typeof Text;
|
|
9
12
|
Caption: typeof Caption;
|
|
10
13
|
Label: typeof Label;
|
|
@@ -21,6 +21,7 @@ const getButtonTheme = (theme: GlobalTheme) => {
|
|
|
21
21
|
textButtonPadding: theme.space.smallMedium,
|
|
22
22
|
iconPadding: theme.space.smallMedium,
|
|
23
23
|
utilityPadding: theme.space.small,
|
|
24
|
+
loadingIndicatorWrapperVerticalPadding: theme.space.xxsmall / 2,
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
const sizes = {
|
package/src/types.ts
CHANGED
|
@@ -15,6 +15,8 @@ import type {
|
|
|
15
15
|
import { SwipeableProps } from './components/Swipeable';
|
|
16
16
|
import { TextProps } from './components/Typography/Text';
|
|
17
17
|
import { CardCarouselHandles } from './components/Carousel/CardCarousel';
|
|
18
|
+
import { FABHandles } from './components/FAB/FAB';
|
|
19
|
+
import { ActionGroupHandles } from './components/FAB/ActionGroup';
|
|
18
20
|
|
|
19
21
|
export type {
|
|
20
22
|
BottomNavigationTabType,
|
|
@@ -32,4 +34,6 @@ export type {
|
|
|
32
34
|
TextInputHandles,
|
|
33
35
|
Theme,
|
|
34
36
|
CardCarouselHandles,
|
|
37
|
+
FABHandles,
|
|
38
|
+
ActionGroupHandles,
|
|
35
39
|
};
|
package/testUtils/setup.tsx
CHANGED
|
@@ -11,6 +11,7 @@ jest.mock('react-native', () => {
|
|
|
11
11
|
const RN = jest.requireActual('react-native');
|
|
12
12
|
|
|
13
13
|
const mockedAnimatedFunctions = {
|
|
14
|
+
setImmediate: () => jest.fn(),
|
|
14
15
|
start: () => jest.fn(),
|
|
15
16
|
stop: () => jest.fn(),
|
|
16
17
|
_isUsingNativeDriver: () => jest.fn(),
|
|
@@ -19,6 +20,7 @@ jest.mock('react-native', () => {
|
|
|
19
20
|
|
|
20
21
|
RN.Animated.timing = () => mockedAnimatedFunctions;
|
|
21
22
|
RN.Animated.spring = () => mockedAnimatedFunctions;
|
|
23
|
+
RN.Animated.stagger = () => mockedAnimatedFunctions;
|
|
22
24
|
|
|
23
25
|
return RN;
|
|
24
26
|
});
|