diff --git a/components/Dropdown/Dropdown.jsx b/components/Dropdown/Dropdown.jsx index dc7391841..f82e64757 100644 --- a/components/Dropdown/Dropdown.jsx +++ b/components/Dropdown/Dropdown.jsx @@ -1,106 +1,45 @@ require('./Dropdown.scss') -import React, { Component, PropTypes } from 'react' +import React, { PropTypes } from 'react' import classNames from 'classnames' - -class Dropdown extends Component { - constructor(props) { - super(props) - - this.state = { isHidden: true } - - this.onClickOutside = this.onClickOutside.bind(this) - this.onClick = this.onClick.bind(this) - this.onClickOtherDropdown = this.onClickOtherDropdown.bind(this) - } - - onClickOutside(evt) { - let currNode = evt.target - let isDropdown = false - - do { - if(currNode.className - && currNode.className.indexOf - && currNode.className.indexOf('dropdown-wrap') > -1) { - isDropdown = true - break +import enhanceDropdown from './enhanceDropdown' + +function Dropdown(props) { + const { className, pointerShadow, noPointer, pointerLeft, isOpen, theme } = props + const ddClasses = classNames('dropdown-wrap', { + [`${className}`] : true, + [`${ theme }`] : true + }) + const ndClasses = classNames('Dropdown', { + 'pointer-shadow' : pointerShadow, + 'pointer-hide' : noPointer, + 'pointer-left' : pointerLeft, + hide : !isOpen + }) + + return ( +
+ { + props.children.map((child) => { + if (child.props.className.indexOf('dropdown-menu-header') > -1) + return child + }) } - currNode = currNode.parentNode - - if(!currNode) - break - } while(currNode.tagName) - - if(!isDropdown) { - this.setState({ isHidden: true }) - } - } - - onClick(evt) { - const dropdownClicked = document.createEvent('Event') - dropdownClicked.initEvent('dropdownClicked', true, false) - - document.dispatchEvent(dropdownClicked) - - this.setState({ isHidden: !this.state.isHidden }) - evt.stopPropagation() - } - - onClickOtherDropdown() { - this.setState({ isHidden: true }) - } - - componentDidMount() { - document.removeEventListener('click', this.onClickOutside) - document.removeEventListener('dropdownClicked', this.onClickOtherDropdown) - - document.addEventListener('click', this.onClickOutside) - document.addEventListener('dropdownClicked', this.onClickOtherDropdown) - } - - componentWillUnmount() { - document.removeEventListener('click', this.onClickOutside) - document.removeEventListener('dropdownClicked', this.onClickOtherDropdown) - } - - render() { - const { className, pointerShadow, noPointer, pointerLeft } = this.props - const ddClasses = classNames('dropdown-wrap', { - [`${className}`] : true, - [`${ this.props.theme }`] : true - }) - const ndClasses = classNames('Dropdown', { - 'pointer-shadow' : pointerShadow, - 'pointer-hide' : noPointer, - 'pointer-left' : pointerLeft, - hide : this.state.isHidden - }) - - return ( -
+
{ - this.props.children.map((child) => { - if (child.props.className.indexOf('dropdown-menu-header') > -1) + props.children.map((child) => { + if (child.props.className.indexOf('dropdown-menu-list') > -1) return child }) } - -
- { - this.props.children.map((child) => { - if (child.props.className.indexOf('dropdown-menu-list') > -1) - return child - }) - } -
- ) - } +
+ ) } Dropdown.propTypes = { children: PropTypes.array.isRequired } -export default Dropdown +export default enhanceDropdown(Dropdown) diff --git a/components/Dropdown/enhanceDropdown.js b/components/Dropdown/enhanceDropdown.js new file mode 100644 index 000000000..16cfee7d3 --- /dev/null +++ b/components/Dropdown/enhanceDropdown.js @@ -0,0 +1,106 @@ +import React, { Component } from 'react' + +const enhanceDropdown = (CompositeComponent) => class extends Component { + constructor(props) { + super(props) + this.state = { isOpen: false } + this.handleClick = this.handleClick.bind(this) + // this.onSelect = this.onSelect.bind(this) + this.onClickOutside = this.onClickOutside.bind(this) + this.onClickOtherDropdown = this.onClickOtherDropdown.bind(this) + this.refreshEventHandlers = this.refreshEventHandlers.bind(this) + } + + refreshEventHandlers() { + if (this.state.isOpen) { + document.addEventListener('click', this.onClickOutside) + document.addEventListener('dropdownClicked', this.onClickOtherDropdown) + } else { + document.removeEventListener('click', this.onClickOutside) + document.removeEventListener('dropdownClicked', this.onClickOtherDropdown) + } + } + + handleClick() { + const dropdownClicked = document.createEvent('Event') + dropdownClicked.initEvent('dropdownClicked', true, false) + + document.dispatchEvent(dropdownClicked) + + this.setState({ isOpen: !this.state.isOpen }, () => { + this.refreshEventHandlers() + }) + } + + // onSelect(value) { + // this.handleClick() + // if (this.props.onSelect) this.props.onSelect(value) + // } + + onClickOutside(evt) { + let currNode = evt.target + let isDropdown = false + console.log('onClickOutside') + + do { + if (currNode.className + && currNode.className.indexOf + && currNode.className.indexOf('dropdown-wrap') > -1) { + isDropdown = true + break + } + + currNode = currNode.parentNode + + if (!currNode) + break + } while (currNode.tagName) + + if (!isDropdown) { + this.setState({ isOpen: false }, () => { + this.refreshEventHandlers() + }) + } + } + + onClickOtherDropdown() { + this.setState({ isOpen: false }, () => { + this.refreshEventHandlers() + }) + } + + componentDidMount() { + document.removeEventListener('click', this.onClickOutside) + document.removeEventListener('dropdownClicked', this.onClickOtherDropdown) + + if (this.state.isOpen) { + document.addEventListener('click', this.onClickOutside) + document.addEventListener('dropdownClicked', this.onClickOtherDropdown) + } + } + + componentWillUnmount() { + document.removeEventListener('click', this.onClickOutside) + document.removeEventListener('dropdownClicked', this.onClickOtherDropdown) + } + + stopEventPropagation(e) { + e.stopPropagation() + } + + render() { + const { isOpen } = this.state + return ( +
+ +
+ ) + } +} + +export default enhanceDropdown \ No newline at end of file diff --git a/components/Forms/images/check-white.svg b/components/Forms/images/check-white.svg new file mode 100644 index 000000000..bd787b05a --- /dev/null +++ b/components/Forms/images/check-white.svg @@ -0,0 +1,16 @@ + + + + Fill 89 + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/components/Formsy/FormFields.scss b/components/Formsy/FormFields.scss index 3047a4e95..8cd787af6 100644 --- a/components/Formsy/FormFields.scss +++ b/components/Formsy/FormFields.scss @@ -269,3 +269,45 @@ a.tiled-group-item { width: 15px; } } + +.SliderRadioGroup { + margin: 25px auto 0px auto; + .rc-slider-dot, + .rc-slider-handle { + background: $tc-white; + border: 4px solid $tc-gray-10; + border-radius: 18px; + width: 20px; + height: 20px; + bottom: -7px; + } + + .rc-slider-handle { + border-color: $tc-dark-blue-90; + margin-left: -4px; + bottom: -2px; + display: none; + } + + &:not(.null-value) .rc-slider-dot-active { + border: none; + background: $tc-dark-blue-90 url('./images/check-white.svg') no-repeat 6px 7px; + // bottom: -2px; + // margin-left: -5px; + } + + .rc-slider-track, + .rc-slider-rail { + background-color: $tc-gray-10; + } + + .rc-slider-mark { + top: -30px; + .rc-slider-mark-text { + @include tc-label-lg; + line-height: 5 * $base_unit; + color: $tc-gray-80; + letter-spacing: 0; + } + } +} diff --git a/components/Formsy/SliderRadioGroup.jsx b/components/Formsy/SliderRadioGroup.jsx index f1555dad0..941d9ad17 100644 --- a/components/Formsy/SliderRadioGroup.jsx +++ b/components/Formsy/SliderRadioGroup.jsx @@ -1,6 +1,8 @@ 'use strict' import React, { Component, PropTypes } from 'react' +import Slider from 'rc-slider' +import 'rc-slider/assets/index.css' import cn from 'classnames' import _ from 'lodash' import { HOC as hoc } from 'formsy-react' @@ -8,29 +10,18 @@ import { HOC as hoc } from 'formsy-react' class SliderRadioGroup extends Component { constructor(props) { super(props) - this.onSlide = this.onSlide.bind(this) + this.onChange = this.onChange.bind(this) } - componentWillMount() { - const idx = Math.max(this.getIndexFromValue(this.props.getValue()), 0) - this.setState({value: idx}) - } - - onChange(idx) { - idx = parseInt(idx) + onChange(value) { const {name, options} = this.props - const newValue = options[idx].value - this.setState({value: idx}) + const newValue = options[value].value this.props.setValue(newValue) this.props.onChange(name, newValue) } noOp() {} - onSlide(event) { - this.onChange(event.target.value) - } - getIndexFromValue(val) { return _.findIndex(this.props.options, (t) => t.value === val) } @@ -39,66 +30,25 @@ class SliderRadioGroup extends Component { const { options, min, max, step} = this.props const value = this.props.getValue() const valueIdx = this.getIndexFromValue(value) - // creating a function to render each type title + desc - const itemFunc = (item, index) => { - // handle active class - const itemClassnames = cn( 'selector', { - active: value === item.value - }) - const idx = this.getIndexFromValue(item.value) - const handleClick = this.onChange.bind(this, idx) - return ( -
-

{item.title}

- {item.desc} -
- ) - } - - // function to render item info - const itemInfoFunc = (item, index) => { - // handle active class - const itemClassnames = cn({active: value === item.value}) - const idx = this.getIndexFromValue(item.value) - const handleClick = this.onChange.bind(this, idx) - return ( - - ) + const marks = {} + for(let i=0; i < options.length; i++) { + marks[i] = options[i].title } return ( - /** - * TODO Using onInput trigger instead of onChange. - * onChange is showing some funky behavior at least in Chrome. - * This functionality should be tested in other browsers - * onChange={this.noOp} - */
- -
- -
- -
- {options.map(itemFunc)} -
- -
- {options.map(itemInfoFunc)} -
- +
) } @@ -113,4 +63,4 @@ SliderRadioGroup.propTypes = { SliderRadioGroup.defaultProps = { onChange: () => {} } -export default hoc(SliderRadioGroup) +export default hoc(SliderRadioGroup) \ No newline at end of file diff --git a/exports.coffee b/exports.coffee index b07cb8444..46f4ea51c 100644 --- a/exports.coffee +++ b/exports.coffee @@ -16,6 +16,7 @@ Tooltip = require './components/Tooltip/Tooltip' Avatar = require './components/Avatar/Avatar' Carousel = require './components/Carousel/Carousel' Checkbox = require './components/Checkbox/Checkbox' +enhanceDropdown = require './components/Dropdown/enhanceDropdown' Dropdown = require './components/Dropdown/Dropdown' DropdownItem = require './components/Dropdown/DropdownItem' SelectDropdown = require './components/SelectDropdown/SelectDropdown' @@ -61,6 +62,7 @@ module.exports = Avatar : Avatar.default Carousel : Carousel.default Checkbox : Checkbox.default + enhanceDropdown : enhanceDropdown.default Dropdown : Dropdown.default DropdownItem : DropdownItem.default SelectDropdown : SelectDropdown.default