Last active
August 29, 2015 13:58
-
-
Save 0m15/9998859 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`/** @jsx React.DOM */` | |
# Component structure: | |
# - DropdownButton | |
# - DropdownMenu | |
# - DropdownMenuItem | |
# refs to some utils | |
classSet = React.addons.classSet | |
# the base dropdown mixin | |
DropdownStateMixin = | |
getInitialState: -> | |
open: false | |
style: | |
position: 'absolute' | |
componentDidMount: -> | |
@setPosition() | |
# handle window resize event | |
$(window).on 'resize', @setPosition | |
bindCloseHandler: -> | |
# handle click outside event | |
document.addEventListener 'click', @handleClickOutside | |
document.addEventListener 'keyup', @handleKeyup | |
unbindCloseHandler: -> | |
document.removeEventListener 'click', @handleClickOutside | |
document.removeEventListener 'keyup', @handleKeyup | |
handleClickOutside: (e) -> | |
@setState | |
open: false | |
@unbindCloseHandler() | |
handleKeyup: (e) -> | |
if e.keyCode is 27 | |
@setState | |
open: false | |
@unbindCloseHandler() | |
handleToggle: (e) -> | |
e.preventDefault() | |
open = [email protected] | |
@setState | |
open: open | |
if open is true | |
@bindCloseHandler() | |
else | |
@unbindCloseHandler() | |
setPosition: -> | |
# ref to btn node | |
$btnEl = $(@refs.button.getDOMNode()) | |
# props and states | |
direction = @props.direction | |
placement = @props.placement | |
style = @state.style | |
# measurements we need to calculate position | |
btnWidth = $btnEl[0].offsetWidth | |
if placement is 'right' | |
style.right = '100%' | |
style['margin-right'] = -1 * btnWidth + 'px' | |
else if placement is 'center' | |
style.left = 0 | |
style['margin-left'] = -1 * btnWidth + 'px' | |
else | |
style.left = 0 | |
if direction is 'up' | |
style.bottom = '100%' | |
else | |
style.top = '100%' | |
@setState | |
style: style | |
@adjustToViewport() | |
adjustToViewport: -> | |
$dropdownEl = $(@refs.menu.getDOMNode()) | |
dropdownMarginRight = parseInt $dropdownEl.css('margin-right') | |
dropdownLeftOffset = $(@refs.button.getDOMNode()).offset().left | |
dropdownWidth = $dropdownEl.width() | |
style = @state.style | |
winWidth = $(window).width() | |
offsetDiff = 0 | |
# check if we've gone outside of the viewport (left) | |
if dropdownLeftOffset < 0 || $dropdownEl.offset().left < 0 | |
offsetDiff = dropdownMarginRight - (-dropdownLeftOffset) | |
if @props.placement is 'right' | |
style['margin-right'] = 0 | |
style['left'] = 0 | |
else | |
style['margin-left'] = 0 | |
style['left'] = 0 | |
# right | |
if dropdownLeftOffset + dropdownWidth > winWidth | |
offsetDiff = (dropdownLeftOffset + $dropdownEl.width()) - winWidth | |
style.left = -1 * offsetDiff + 'px' | |
@setState | |
style: style | |
DropdownButton = React.createClass | |
mixins: [DropdownStateMixin] | |
render: -> | |
classes = classSet | |
open: @state.open | |
dropdown: true | |
up: @props.direction == 'up' | |
down: @props.direction == 'down' | |
`<div className={classes}> | |
<a href="" onClick={this.handleToggle} className="btn btn-dropdown" ref="button"> | |
{this.props.title} <i className="icon-caret"></i> | |
</a> | |
<DropdownMenu ref="menu" items={this.props.items} onSelect={this.props.onSelect} style={this.state.style} /> | |
</div> | |
` | |
DropdownMenu = React.createClass | |
render: -> | |
`<ul className="dropdown-menu" style={this.props.style}> | |
{this.props.items.map(function(item, i) { | |
return (<DropdownMenuItem item={item} onSelect={this.props.onSelect} key={i} />) | |
}, this)} | |
</ul> | |
` | |
DropdownMenuItem = React.createClass | |
render: -> | |
`<li> | |
<a href="" onClick={this.handleClick}>{this.props.item.title}</a> | |
</li>` | |
handleClick: (e) -> | |
e.preventDefault() | |
@props.onSelect(@props.item) | |
DropdownExample = React.createClass | |
render: -> | |
@transferPropsTo `<DropdownButton | |
placement="left" | |
direction="down" | |
onSelect={this.handleSelect} />` | |
handleSelect: (item) -> | |
console.log 'selected', item | |
items = [ | |
{ title: 'item 1' } | |
{ title: 'item 2' } | |
{ title: 'item 3' } | |
] | |
React.renderComponent( `<DropdownExample items={items} title="show menu" />`, document.getElementById('content')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment