-
Notifications
You must be signed in to change notification settings - Fork 7
/
DropdownWrapper.jsx
111 lines (94 loc) · 3.16 KB
/
DropdownWrapper.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { TimelineMax } from 'gsap/TweenMax';
import PropTypes from 'prop-types';
import React from 'react';
import onClickOutside from 'react-onclickoutside';
import { UtilitySystem } from '.';
class DropdownWrapper extends React.Component {
componentDidMount = () => {
const $dropdown = this.dropdown;
const $dropdownMenu = $dropdown.querySelector('.dropdown__menu');
const $dropdownToggle = $dropdown.querySelector('.dropdown__toggle');
let forward = true;
let lastTime = 0;
// Attach GSAP
$dropdown.timeline = new TimelineMax({
paused: true,
onStart: () => {
// Add active/open classes
$dropdown.classList.add(UtilitySystem.config.classes.open);
if ($dropdownToggle) {
$dropdownToggle.classList.add(UtilitySystem.config.classes.active);
}
// Toggle aria state
$dropdown.setAttribute('aria-expanded', true);
// Fire off prop update
if (this.props.onStart) this.props.onStart();
},
onComplete: () => {
const $input = $dropdown.querySelector('input[type="text"]');
// If dropdown contains input (for filtering), focus on that if autoFocusInput props is true or undefined
if ($input && this.props.autoFocusInput) {
$input.focus();
} else {
// Focus on active dropdown
$dropdown.focus();
}
// Fire off prop update
if (this.props.onComplete) this.props.onComplete();
},
onUpdate: () => {
const newTime = $dropdown.timeline.time();
if ((forward && newTime < lastTime) || (!forward && newTime > lastTime)) {
forward = !forward;
if (!forward) {
// Fire off prop update
if (this.props.onReverseStart) this.props.onReverseStart();
// Remove active/open classes
$dropdown.classList.remove(UtilitySystem.config.classes.open);
if ($dropdownToggle) {
$dropdownToggle.classList.remove(UtilitySystem.config.classes.active);
}
// Toggle aria state
$dropdown.setAttribute('aria-expanded', false);
}
}
lastTime = newTime;
},
onReverseComplete: () => {
// Fire off prop update
if (this.props.onReverseComplete) this.props.onReverseComplete();
},
});
$dropdown.timeline
.set($dropdownMenu, {
display: 'block',
})
.to($dropdownMenu, 0.175, {
css: {
y: 0,
scale: 1,
opacity: 1,
},
ease: UtilitySystem.config.easingBounce,
});
}
handleClickOutside = () => {
this.props.handleClick();
}
render() {
return (
<div aria-haspopup="true" aria-expanded="false" ref={ref => (this.dropdown = ref)} className={this.props.className}>{this.props.children}</div>
);
}
}
DropdownWrapper.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
handleClick: PropTypes.func,
onComplete: PropTypes.func,
onReverseComplete: PropTypes.func,
onReverseStart: PropTypes.func,
onStart: PropTypes.func,
autoFocusInput: PropTypes.bool,
};
export default onClickOutside(DropdownWrapper);