Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions example/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FlatArrayExample from './flatArrayExample'
import ObjectArrayExample from './objectArrayExample'
import ZeroValObjectArrayExample from './zeroValObjectArrayExample'
import CustomArrowExample from './CustomArrowExample'
import OpenCloseAnimationExample from './openCloseAnimationExample'

class App extends Component {
render () {
Expand Down Expand Up @@ -40,6 +41,7 @@ class App extends Component {
<ObjectArrayExample />
<ZeroValObjectArrayExample />
<CustomArrowExample />
<OpenCloseAnimationExample />

<section>
<h3>License: </h3>
Expand Down
38 changes: 38 additions & 0 deletions example/openCloseAnimationExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { Component } from 'react'
import Dropdown from '../index.js'

const options = [
'one', 'two', 'three'
]

class OpenCloseAnimationExample extends Component {
render () {
return (
<section className="open-close-animation-example">
<h3>Open/Close Animation Example</h3>
<Dropdown
options={options}
placeholder="Select an option"
closeDelayMS={500}
/>

<section>
<h4>Usage: </h4>
<div className='code'>
<pre>
{`
<Dropdown
options={options}
placeholder="Select an option"
closeDelayMS={500}
/>
`}
</pre>
</div>
</section>
</section>
)
}
}

export default OpenCloseAnimationExample
48 changes: 48 additions & 0 deletions example/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,51 @@ pre code {
color: purple;
}

@keyframes open-animation {
0% {
overflow-y: hidden;
max-height: 0;
}

99% {
overflow-y: hidden;
}

100% {
overflow-y: auto;
max-height: 200px;
}
}

@keyframes close-animation {
0% {
overflow-y: hidden;
max-height: 200px;
}

100% {
max-height: 0;
overflow-y: hidden;
}
}

.open-close-animation-example .Dropdown-menu {
animation-name: open-animation;
animation-duration: 0.5s;
}

.open-close-animation-example .is-closing .Dropdown-menu {
animation-name: close-animation;
animation-duration: 0.5s;
max-height: 0;
}

.open-close-animation-example .Dropdown-arrow {
transition: transform 0.5s;
}

.open-close-animation-example .is-open .Dropdown-arrow {
transform: rotate(180deg);
border-color: #999 transparent transparent;
border-width: 5px 5px 0;
}
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ declare module "react-dropdown" {
onFocus?: (arg: boolean) => void;
value?: Option | string;
placeholder?: String;
closeDelayMS?: number;
}

class ReactDropdown extends React.Component<ReactDropdownProps> {
Expand Down
64 changes: 54 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ class Dropdown extends Component {
label: typeof props.placeholder === 'undefined' ? DEFAULT_PLACEHOLDER_STRING : props.placeholder,
value: ''
},
isOpen: false
showMenu: false,
isOpen: false,
isClosing: false
}
this.dropdownRef = createRef()
this.timerRef = createRef()
this.mounted = true
this.handleDocumentClick = this.handleDocumentClick.bind(this)
this.fireChangeEvent = this.fireChangeEvent.bind(this)
Expand Down Expand Up @@ -46,6 +49,48 @@ class Dropdown extends Component {
this.mounted = false
document.removeEventListener('click', this.handleDocumentClick, false)
document.removeEventListener('touchend', this.handleDocumentClick, false)

clearTimeout(this.timerRef.current)
}

open () {
this.setState({
showMenu: true,
isOpen: false,
isClosing: false
})

clearTimeout(this.timerRef.current)

this.timerRef.current = setTimeout(() => {
this.setState({
showMenu: true,
isOpen: true,
isClosing: false
})
}, 0)
}

close () {
this.setState({
showMenu: true,
isOpen: false,
isClosing: true
})

clearTimeout(this.timerRef.current)

this.timerRef.current = setTimeout(() => {
this.setState({
showMenu: false,
isOpen: false,
isClosing: false
})
}, this.props.closeDelayMS || 0)
}

toggle (open) {
open ? this.open() : this.close()
}

handleMouseDown (event) {
Expand All @@ -57,9 +102,7 @@ class Dropdown extends Component {
event.preventDefault()

if (!this.props.disabled) {
this.setState({
isOpen: !this.state.isOpen
})
this.toggle(!this.state.isOpen)
}
}

Expand All @@ -86,11 +129,11 @@ class Dropdown extends Component {
let newState = {
selected: {
value,
label},
isOpen: false
label}
}
this.fireChangeEvent(newState)
this.setState(newState)
this.toggle(false)
}

fireChangeEvent (newState) {
Expand Down Expand Up @@ -167,7 +210,7 @@ class Dropdown extends Component {
if (this.mounted) {
if (!this.dropdownRef.current.contains(event.target)) {
if (this.state.isOpen) {
this.setState({ isOpen: false })
this.toggle(false)
}
}
}
Expand All @@ -186,7 +229,8 @@ class Dropdown extends Component {
const dropdownClass = classNames({
[`${baseClassName}-root`]: true,
[className]: !!className,
'is-open': this.state.isOpen
'is-open': this.state.isOpen,
'is-closing': this.state.isClosing
})
const controlClass = classNames({
[`${baseClassName}-control`]: true,
Expand All @@ -210,7 +254,7 @@ class Dropdown extends Component {
const value = (<div className={placeholderClass}>
{placeHolderValue}
</div>)
const menu = this.state.isOpen ? <div className={menuClass} aria-expanded='true'>
const menu = this.state.showMenu ? <div className={menuClass} aria-expanded='true'>
{this.buildMenu()}
</div> : null

Expand All @@ -220,7 +264,7 @@ class Dropdown extends Component {
{value}
<div className={`${baseClassName}-arrow-wrapper`}>
{arrowOpen && arrowClosed
? this.state.isOpen ? arrowOpen : arrowClosed
? this.state.showMenu ? arrowOpen : arrowClosed
: <span className={arrowClass} />}
</div>
</div>
Expand Down
Loading