Skip to content

Commit 559b469

Browse files
jseminckCompuIves
authored andcommitted
Add animation when sub-modes disappear in the header (codesandbox#145)
* Add hover animation to sub modes * Keep the current sub modes visible until the animation has ended
1 parent b842a0a commit 559b469

File tree

1 file changed

+83
-19
lines changed

1 file changed

+83
-19
lines changed

src/app/components/sandbox/ModeIcons.js

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,46 @@ import styled, { keyframes } from 'styled-components';
33

44
import Tooltip from 'app/components/Tooltip';
55

6-
const animation = keyframes`
6+
const showAnimationKeyframes = keyframes`
77
0% { opacity: 0; transform: translateX(10px); }
88
100% { opacity: 1; transform: translateX(0px); }
99
`;
1010

11-
const reverseAnimation = keyframes`
11+
const reverseShowAnimationKeyframes = keyframes`
1212
0% { opacity: 0; transform: translateX(-10px); }
1313
100% { opacity: 1; transform: translateX(0px); }
1414
`;
1515

16-
const delayAnimation = (delay: number = 0, reverse: boolean = true) =>
16+
const showAnimation = (delay: number = 0, reverse: boolean = true) =>
1717
`
18-
animation: ${reverse ? reverseAnimation : animation} 0.3s;
18+
animation: ${reverse
19+
? reverseShowAnimationKeyframes
20+
: showAnimationKeyframes} 0.3s;
1921
animation-delay: ${delay}s;
2022
animation-fill-mode: forwards;
2123
opacity: 0;
2224
`;
2325

26+
const hideAnimationKeyframes = keyframes`
27+
0% { opacity: 1; transform: translateX(0px); }
28+
100% { opacity: 0; transform: translateX(10px); }
29+
`;
30+
31+
const reverseHideAnimationKeyframes = keyframes`
32+
0% { opacity: 1; transform: translateX(0px); }
33+
100% { opacity: 0; transform: translateX(-10px); }
34+
`;
35+
36+
const hideAnimation = (delay: number = 0, reverse: boolean = true) =>
37+
`
38+
animation: ${reverse
39+
? reverseHideAnimationKeyframes
40+
: hideAnimationKeyframes} 0.3s;
41+
animation-delay: ${delay}s;
42+
animation-fill-mode: forwards;
43+
opacity: 1;
44+
`;
45+
2446
const Tooltips = styled.div`
2547
display: flex;
2648
align-items: center;
@@ -69,7 +91,10 @@ const Hover = styled.div`
6991
`;
7092

7193
const SubMode = styled.div`
72-
${props => delayAnimation(props.i * 0.05, props.i === 1)};
94+
${props =>
95+
props.hovering
96+
? showAnimation(props.i * 0.05, props.i === 1)
97+
: hideAnimation(props.i * 0.05, props.i === 1)};
7398
`;
7499

75100
const Icon = styled.div`
@@ -94,15 +119,15 @@ type Props = {
94119
setEditorView: () => void,
95120
setPreviewView: () => void,
96121
setMixedView: () => void,
97-
noPreview: ?boolean,
122+
noPreview: ?boolean
98123
};
99124

100125
const getCurrentMode = ({
101126
showEditor,
102127
showPreview,
103128
setMixedView,
104129
setEditorView,
105-
setPreviewView,
130+
setPreviewView
106131
}: Props) => {
107132
const both = (
108133
<ViewIcon onClick={setMixedView} active={showEditor && showPreview}>
@@ -132,53 +157,92 @@ const getCurrentMode = ({
132157
};
133158

134159
export default class ModeIcons extends React.PureComponent<Props> {
135-
state = {
136-
hovering: false,
137-
};
160+
constructor(props) {
161+
super(props);
162+
163+
const { currentMode, otherModes } = getCurrentMode(this.props);
164+
165+
this.state = {
166+
hovering: false,
167+
showSubmodes: false,
168+
currentMode,
169+
otherModes
170+
};
171+
}
138172

139173
onMouseEnter = () => {
140174
this.setState({
141-
hovering: true,
175+
showSubmodes: true,
176+
hovering: true
142177
});
143178
};
144179

145180
onMouseLeave = () => {
146181
this.setState({
147-
hovering: false,
182+
hovering: false
148183
});
149184
};
150185

186+
onAnimationEnd = () => {
187+
const { currentMode, otherModes } = getCurrentMode(this.props);
188+
189+
if (!this.state.hovering) {
190+
this.setState({
191+
showSubmodes: false,
192+
currentMode,
193+
otherModes
194+
});
195+
}
196+
};
197+
198+
componentWillReceiveProps(nextProps) {
199+
const { currentMode, otherModes } = getCurrentMode(nextProps);
200+
201+
if (!this.state.hovering) {
202+
this.setState({
203+
currentMode,
204+
otherModes
205+
});
206+
} else {
207+
this.setState({
208+
currentMode
209+
});
210+
}
211+
}
212+
151213
render() {
152214
const {
153215
showEditor,
154216
showPreview,
155217
setEditorView,
156218
setMixedView,
157219
setPreviewView,
158-
dropdown,
220+
dropdown
159221
} = this.props;
160222

161-
if (dropdown) {
162-
const { currentMode, otherModes } = getCurrentMode(this.props);
223+
const { hovering, showSubmodes, currentMode, otherModes } = this.state;
163224

225+
if (dropdown) {
164226
return (
165227
<Tooltips>
166228
<Hover onMouseLeave={this.onMouseLeave}>
167-
{this.state.hovering &&
229+
{showSubmodes &&
168230
<SubMode
169231
onClick={this.onMouseLeave}
170-
hovering={this.state.hovering}
232+
onAnimationEnd={this.onAnimationEnd}
233+
hovering={hovering}
171234
i={0}
172235
>
173236
{otherModes[0]}
174237
</SubMode>}
175238
<div onMouseEnter={this.onMouseEnter}>
176239
{currentMode}
177240
</div>
178-
{this.state.hovering &&
241+
{showSubmodes &&
179242
<SubMode
180243
onClick={this.onMouseLeave}
181-
hovering={this.state.hovering}
244+
onAnimationEnd={this.onAnimationEnd}
245+
hovering={hovering}
182246
i={1}
183247
>
184248
{otherModes[1]}

0 commit comments

Comments
 (0)