@hero-design/rn 8.35.0 → 8.35.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 +39 -13
- package/lib/index.js +39 -13
- package/package.json +7 -7
- package/src/components/FAB/ActionGroup/StyledActionGroup.tsx +12 -0
- package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +801 -1251
- package/src/components/FAB/ActionGroup/__tests__/index.spec.tsx +45 -35
- package/src/components/FAB/ActionGroup/index.tsx +65 -45
- package/src/components/Portal/PortalHost.tsx +3 -0
- package/src/components/Portal/PortalProvider.tsx +6 -0
- package/src/components/Portal/index.tsx +11 -0
- package/types/components/FAB/ActionGroup/StyledActionGroup.d.ts +7 -1
|
@@ -10,52 +10,53 @@ describe('ActionGroup', () => {
|
|
|
10
10
|
${true}
|
|
11
11
|
${false}
|
|
12
12
|
`('has active $active', ({ active }) => {
|
|
13
|
-
const { toJSON, getByTestId, getByText } =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
13
|
+
const { toJSON, getByTestId, getByText, queryByTestId, queryByText } =
|
|
14
|
+
renderWithTheme(
|
|
15
|
+
<ActionGroup
|
|
16
|
+
fabTitle="Shout out"
|
|
17
|
+
active={active}
|
|
18
|
+
headerTitle="What would you like to create?"
|
|
19
|
+
items={[
|
|
20
|
+
{
|
|
21
|
+
icon: 'speaker',
|
|
22
|
+
title: 'Give shout out',
|
|
23
|
+
testID: 'speaker-action-item',
|
|
24
|
+
},
|
|
25
|
+
{ icon: 'target', title: 'Goal', testID: 'target-action-item' },
|
|
26
|
+
{
|
|
27
|
+
icon: 'plane',
|
|
28
|
+
title: 'Leave request',
|
|
29
|
+
testID: 'plane-action-item',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
icon: 'health-bag',
|
|
33
|
+
title: 'Safety incident',
|
|
34
|
+
testID: 'health-bag-action-item',
|
|
35
|
+
},
|
|
36
|
+
{ icon: 'clock', title: 'Timesheets', testID: 'clock-action-item' },
|
|
37
|
+
]}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
39
40
|
|
|
40
41
|
expect(toJSON()).toMatchSnapshot();
|
|
41
42
|
|
|
42
|
-
expect(getByText('What would you like to create?')).toBeDefined();
|
|
43
|
-
expect(getByTestId('speaker-action-item')).toBeDefined();
|
|
44
|
-
expect(getByTestId('target-action-item')).toBeDefined();
|
|
45
|
-
expect(getByTestId('plane-action-item')).toBeDefined();
|
|
46
|
-
expect(getByTestId('health-bag-action-item')).toBeDefined();
|
|
47
|
-
|
|
48
43
|
if (active) {
|
|
49
44
|
// verify backdrop appears
|
|
50
|
-
expect(
|
|
45
|
+
expect(queryByTestId('back-drop')).toBeDefined();
|
|
46
|
+
expect(getByText('What would you like to create?')).toBeDefined();
|
|
47
|
+
expect(getByTestId('speaker-action-item')).toBeDefined();
|
|
48
|
+
expect(getByTestId('target-action-item')).toBeDefined();
|
|
49
|
+
expect(getByTestId('plane-action-item')).toBeDefined();
|
|
50
|
+
expect(getByTestId('health-bag-action-item')).toBeDefined();
|
|
51
51
|
} else {
|
|
52
52
|
// verify backdrop disappears
|
|
53
|
-
expect(
|
|
53
|
+
expect(queryByTestId('back-drop')).toBeNull();
|
|
54
|
+
expect(queryByText('What would you like to create?')).toBeNull();
|
|
54
55
|
}
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
describe('when user presses', () => {
|
|
58
|
-
it('calls onPress', () => {
|
|
59
|
+
it('calls onPress when active = false', () => {
|
|
59
60
|
const onPressSpy = jest.fn();
|
|
60
61
|
const { getByTestId } = renderWithTheme(
|
|
61
62
|
<ActionGroup onPress={onPressSpy} />
|
|
@@ -63,5 +64,14 @@ describe('ActionGroup', () => {
|
|
|
63
64
|
fireEvent(getByTestId('fab'), 'press');
|
|
64
65
|
expect(onPressSpy).toBeCalledTimes(1);
|
|
65
66
|
});
|
|
67
|
+
|
|
68
|
+
it('calls onPress when active = true', () => {
|
|
69
|
+
const onPressSpy = jest.fn();
|
|
70
|
+
const { getByTestId } = renderWithTheme(
|
|
71
|
+
<ActionGroup onPress={onPressSpy} active />
|
|
72
|
+
);
|
|
73
|
+
fireEvent(getByTestId('fab-in-portal'), 'press');
|
|
74
|
+
expect(onPressSpy).toBeCalledTimes(1);
|
|
75
|
+
});
|
|
66
76
|
});
|
|
67
77
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, useRef } from 'react';
|
|
2
2
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { Animated, Platform } from 'react-native';
|
|
3
|
+
import { Animated, Platform, Modal } from 'react-native';
|
|
4
4
|
import type { IconName } from '../../Icon';
|
|
5
5
|
import type { ActionItemProps } from './ActionItem';
|
|
6
6
|
import ActionItem from './ActionItem';
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
StyledActionGroupContainer,
|
|
9
9
|
StyledBackdrop,
|
|
10
10
|
StyledContainer,
|
|
11
|
+
StyledContainerInModal,
|
|
11
12
|
StyledFAB,
|
|
12
13
|
StyledHeaderText,
|
|
13
14
|
} from './StyledActionGroup';
|
|
@@ -110,64 +111,83 @@ const ActionGroup = forwardRef<ActionGroupHandles, ActionGroupProps>(
|
|
|
110
111
|
}),
|
|
111
112
|
]).start();
|
|
112
113
|
}, [active]);
|
|
113
|
-
|
|
114
|
-
const interpolatedBackdropOpacityAnimation =
|
|
114
|
+
const interpolatedActionGroupOpacityAnimation =
|
|
115
115
|
tranlateXAnimation.current.interpolate({
|
|
116
116
|
inputRange: [0, 1],
|
|
117
|
-
outputRange: [0,
|
|
117
|
+
outputRange: [0, 1],
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
const
|
|
120
|
+
const interpolatedFABOpacityAnimation =
|
|
121
121
|
tranlateXAnimation.current.interpolate({
|
|
122
122
|
inputRange: [0, 1],
|
|
123
|
-
outputRange: [
|
|
123
|
+
outputRange: [1, 0],
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
return (
|
|
127
127
|
<StyledContainer testID={testID} pointerEvents="box-none" style={style}>
|
|
128
|
-
<
|
|
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"
|
|
128
|
+
<Animated.View
|
|
136
129
|
style={{
|
|
137
|
-
opacity:
|
|
130
|
+
opacity: interpolatedFABOpacityAnimation,
|
|
138
131
|
}}
|
|
139
132
|
>
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
133
|
+
<StyledFAB
|
|
134
|
+
key="fab"
|
|
135
|
+
testID="fab"
|
|
136
|
+
icon={fabIcon}
|
|
137
|
+
onPress={onPress}
|
|
138
|
+
animated
|
|
139
|
+
active={active}
|
|
140
|
+
title={fabTitle}
|
|
141
|
+
ref={fabRef}
|
|
142
|
+
/>
|
|
143
|
+
</Animated.View>
|
|
144
|
+
<Modal
|
|
145
|
+
visible={active}
|
|
146
|
+
animationType="fade"
|
|
147
|
+
transparent
|
|
148
|
+
statusBarTranslucent
|
|
149
|
+
>
|
|
150
|
+
<StyledContainerInModal testID={testID} style={[style]}>
|
|
151
|
+
<StyledBackdrop testID="back-drop" />
|
|
152
|
+
<StyledActionGroupContainer
|
|
153
|
+
testID="action-group"
|
|
154
|
+
style={{
|
|
155
|
+
opacity: interpolatedActionGroupOpacityAnimation,
|
|
156
|
+
}}
|
|
143
157
|
>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
158
|
+
{!!headerTitle && (
|
|
159
|
+
<Animated.View
|
|
160
|
+
style={{ transform: [{ translateY: titleTranslateY }] }}
|
|
161
|
+
>
|
|
162
|
+
<StyledHeaderText testID="header-text" level="h4">
|
|
163
|
+
{headerTitle}
|
|
164
|
+
</StyledHeaderText>
|
|
165
|
+
</Animated.View>
|
|
166
|
+
)}
|
|
167
|
+
|
|
168
|
+
<Box style={[style, { paddingBottom: 0 }]}>
|
|
169
|
+
{items?.map((itemProp, index) => (
|
|
170
|
+
<ActionItem
|
|
171
|
+
key={itemProp.key || `${itemProp.icon}_${itemProp.title}`}
|
|
172
|
+
{...itemProp}
|
|
173
|
+
index={active ? index : items.length - index}
|
|
174
|
+
active={active}
|
|
175
|
+
/>
|
|
176
|
+
))}
|
|
177
|
+
</Box>
|
|
178
|
+
</StyledActionGroupContainer>
|
|
179
|
+
|
|
180
|
+
<StyledFAB
|
|
181
|
+
key="fab-in-portal"
|
|
182
|
+
testID="fab-in-portal"
|
|
183
|
+
icon={fabIcon}
|
|
184
|
+
onPress={onPress}
|
|
185
|
+
animated
|
|
186
|
+
active={active}
|
|
187
|
+
title={fabTitle}
|
|
188
|
+
/>
|
|
189
|
+
</StyledContainerInModal>
|
|
190
|
+
</Modal>
|
|
171
191
|
</StyledContainer>
|
|
172
192
|
);
|
|
173
193
|
}
|
|
@@ -6,7 +6,13 @@ import { INITIAL_STATE } from './constants';
|
|
|
6
6
|
import { PortalDispatchContext, PortalStateContext } from './contexts';
|
|
7
7
|
|
|
8
8
|
export interface PortalProviderProps {
|
|
9
|
+
/*
|
|
10
|
+
* The name of the root host
|
|
11
|
+
*/
|
|
9
12
|
rootHostName?: string;
|
|
13
|
+
/*
|
|
14
|
+
* The children to render
|
|
15
|
+
*/
|
|
10
16
|
children: ReactNode | ReactNode[];
|
|
11
17
|
}
|
|
12
18
|
|
|
@@ -9,8 +9,19 @@ import { PortalHost } from './PortalHost';
|
|
|
9
9
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 10);
|
|
10
10
|
|
|
11
11
|
export interface PortalProps {
|
|
12
|
+
/*
|
|
13
|
+
* Name of the portal. If name is not provided, a random name will be generated.
|
|
14
|
+
*/
|
|
12
15
|
name?: string;
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* Name of the portal host. If name is not provided, a default host will be used.
|
|
19
|
+
*/
|
|
13
20
|
hostName?: string;
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Content of the portal.
|
|
24
|
+
*/
|
|
14
25
|
children?: ReactNode | ReactNode[];
|
|
15
26
|
}
|
|
16
27
|
|
|
@@ -8,6 +8,12 @@ declare const StyledContainer: import("@emotion/native").StyledComponent<ViewPro
|
|
|
8
8
|
}, {}, {
|
|
9
9
|
ref?: import("react").Ref<View> | undefined;
|
|
10
10
|
}>;
|
|
11
|
+
declare const StyledContainerInModal: import("@emotion/native").StyledComponent<ViewProps & {
|
|
12
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
13
|
+
as?: import("react").ElementType<any> | undefined;
|
|
14
|
+
}, {}, {
|
|
15
|
+
ref?: import("react").Ref<View> | undefined;
|
|
16
|
+
}>;
|
|
11
17
|
declare const StyledActionGroupContainer: import("@emotion/native").StyledComponent<Animated.AnimatedProps<ViewProps & import("react").RefAttributes<View>> & {
|
|
12
18
|
children?: import("react").ReactNode;
|
|
13
19
|
} & {
|
|
@@ -28,4 +34,4 @@ declare const StyledHeaderText: import("@emotion/native").StyledComponent<import
|
|
|
28
34
|
theme?: import("@emotion/react").Theme | undefined;
|
|
29
35
|
as?: import("react").ElementType<any> | undefined;
|
|
30
36
|
} & TextProps, {}, {}>;
|
|
31
|
-
export { StyledHeaderText, StyledBackdrop, StyledContainer, StyledActionGroupContainer, StyledFAB, };
|
|
37
|
+
export { StyledHeaderText, StyledBackdrop, StyledContainer, StyledContainerInModal, StyledActionGroupContainer, StyledFAB, };
|