rc-select
Advanced tools
Comparing version
var React = require('react'); | ||
var Select = require('../'); | ||
var Option = Select.Option; | ||
require('./examples.css'); | ||
require('rc-menu/assets/index.css'); | ||
@@ -6,0 +5,0 @@ require('rc-select/assets/index.css'); |
var React = require('react'); | ||
var Select = require('rc-select'); | ||
var Option = Select.Option; | ||
require('./examples.css'); | ||
require('rc-menu/assets/index.css'); | ||
@@ -16,3 +15,3 @@ require('rc-select/assets/index.css'); | ||
var style = '.rc-select-menu {height:200px;overflow:auto;}'; | ||
var style = '.rc-select-menu {max-height:200px;overflow:auto;}'; | ||
@@ -19,0 +18,0 @@ var c2 = ( |
var React = require('react'); | ||
var Select = require('rc-select'); | ||
var Option = Select.Option; | ||
require('./examples.css'); | ||
require('rc-menu/assets/index.css'); | ||
@@ -6,0 +5,0 @@ require('rc-select/assets/index.css'); |
@@ -14,21 +14,24 @@ /** @jsx React.DOM */ | ||
function isMultipleOrTags(props) { | ||
return props.multiple || props.tags; | ||
} | ||
function noop() { | ||
} | ||
function getKeyFromOptionChild(child) { | ||
function getValueFromOptionChild(child) { | ||
var optionProps = child.props; | ||
var children = optionProps.children; | ||
var ret = child.key || undefined; | ||
if (!ret) { | ||
var ret; | ||
if (optionProps.value !== undefined) { | ||
if (typeof optionProps.value === 'string') { | ||
ret = optionProps.value; | ||
} else if (React.isValidElement(children)) { | ||
if (typeof children.props.children === 'string') { | ||
ret = children.props.children; | ||
} | ||
} | ||
} else if (typeof children === 'string') { | ||
ret = children; | ||
} | ||
if (!ret && !child.props.disabled) { | ||
throw new Error('please set key on Option element!'); | ||
throw new Error('must set value string on Option element!'); | ||
} | ||
return ret; | ||
@@ -39,3 +42,4 @@ } | ||
var ret = { | ||
key: getKeyFromOptionChild(child) | ||
key: getValueFromOptionChild(child), | ||
value: getValueFromOptionChild(child) | ||
}; | ||
@@ -86,9 +90,35 @@ var optionProps = child.props; | ||
_getFilterList(searchText) { | ||
renderFilterOptions() { | ||
var inputValue = this.state.inputValue; | ||
var sel = []; | ||
React.Children.forEach(this.props.children, (child)=> { | ||
if (!searchText || !child.props.disabled && getKeyFromOptionChild(child).indexOf(searchText) > -1) { | ||
var props = this.props; | ||
var childrenKeys = []; | ||
React.Children.forEach(props.children, (child)=> { | ||
if (!inputValue || !child.props.disabled && getValueFromOptionChild(child).indexOf(inputValue) > -1) { | ||
sel.push(child); | ||
} | ||
if (!child.props.disabled) { | ||
childrenKeys.push(getValueFromOptionChild(child)); | ||
} | ||
}); | ||
if (props.tags) { | ||
var value = this.state.value || []; | ||
value = value.filter((v)=> { | ||
return childrenKeys.indexOf(v) === -1 && (!inputValue || v.indexOf(inputValue) > -1); | ||
}); | ||
sel = sel.concat(value.map((v)=> { | ||
return <MenuItem value={v}>{v}</MenuItem>; | ||
})); | ||
if (inputValue) { | ||
var notFindInputItem = sel.every((s)=> { | ||
return getValueFromOptionChild(s) !== inputValue; | ||
}); | ||
if (notFindInputItem) { | ||
sel.unshift(<MenuItem value={inputValue}>{inputValue}</MenuItem>); | ||
} | ||
} | ||
} | ||
if (!sel.length) { | ||
sel = <MenuItem disabled value='NOT_FOUND'>{props.notFoundContent}</MenuItem>; | ||
} | ||
return sel; | ||
@@ -101,3 +131,3 @@ } | ||
}, ()=> { | ||
if (open || this.props.multiple || this.props.combobox) { | ||
if (open || isMultipleOrTags(this.props) || this.props.combobox) { | ||
this.refs.input.getDOMNode().focus(); | ||
@@ -165,3 +195,3 @@ } else { | ||
var value; | ||
if (this.props.multiple) { | ||
if (isMultipleOrTags(this.props)) { | ||
value = this.state.value.concat(); | ||
@@ -176,3 +206,3 @@ value.push(item.props.value); | ||
} | ||
this.props.onChange(this.props.multiple ? value : value[0]); | ||
this.props.onChange(isMultipleOrTags(this.props) ? value : value[0]); | ||
this.setState({ | ||
@@ -190,4 +220,9 @@ value: value, | ||
handleMenuDeselect(key, item) { | ||
this.removeSelected(item.props.value); | ||
handleMenuDeselect(key, item, e) { | ||
if (e.type === 'click') { | ||
this.removeSelected(item.props.value); | ||
} | ||
this.setState({ | ||
inputValue: '' | ||
}); | ||
this.setOpenState(false); | ||
@@ -217,3 +252,3 @@ } | ||
}); | ||
this.props.onChange(this.props.multiple ? value : value[0]); | ||
this.props.onChange(isMultipleOrTags(this.props) ? value : value[0]); | ||
this.setState({ | ||
@@ -227,3 +262,3 @@ value: value | ||
if (this.state.value.length) { | ||
this.props.onChange(this.props.multiple ? [] : undefined); | ||
this.props.onChange(isMultipleOrTags(this.props) ? [] : undefined); | ||
this.setState({ | ||
@@ -240,3 +275,3 @@ value: [], | ||
var menuProps = {}; | ||
if (props.multiple) { | ||
if (isMultipleOrTags(props)) { | ||
menuProps.onDeselect = this.handleMenuDeselect; | ||
@@ -261,3 +296,3 @@ } | ||
activeKey={activeKey} | ||
multiple={props.multiple} | ||
multiple={isMultipleOrTags(props)} | ||
focusable={false} | ||
@@ -271,3 +306,3 @@ {...menuProps} | ||
getTopControlNode(input) { | ||
renderTopControlNode(input) { | ||
var value = this.state.value; | ||
@@ -280,3 +315,3 @@ var prefixCls = this.props.prefixCls; | ||
// single and not combobox, input is inside dropdown | ||
if (!props.combobox && !props.multiple) { | ||
if (!props.combobox && !isMultipleOrTags(props)) { | ||
return <span className={prefixCls + '-selection__rendered'}> | ||
@@ -288,3 +323,3 @@ {value[0]} | ||
var selectedValueNodes; | ||
if (props.multiple) { | ||
if (isMultipleOrTags(props)) { | ||
selectedValueNodes = value.map((v) => { | ||
@@ -304,3 +339,3 @@ return ( | ||
{selectedValueNodes} | ||
{allowClear && !props.multiple ? clear : null} | ||
{allowClear && !isMultipleOrTags(props) ? clear : null} | ||
<li className={joinClasses(prefixCls + '-search', prefixCls + '-search--inline')}>{input}</li> | ||
@@ -335,3 +370,4 @@ </ul> | ||
var props = this.props; | ||
var multiple = props.multiple; | ||
var multiple = isMultipleOrTags(props); | ||
var state = this.state; | ||
var prefixCls = props.prefixCls; | ||
@@ -343,3 +379,3 @@ | ||
onKeyDown={this.handleInputKeyDown} | ||
value={this.state.inputValue} | ||
value={state.inputValue} | ||
className={prefixCls + '-search__field'} | ||
@@ -349,10 +385,6 @@ role="textbox" /> | ||
var children = this._getFilterList(this.state.inputValue); | ||
if (!children.length) { | ||
children = <MenuItem disabled>{props.notFoundContent}</MenuItem>; | ||
} | ||
var ctrlNode = this.getTopControlNode(input); | ||
var children = this.renderFilterOptions(); | ||
var ctrlNode = this.renderTopControlNode(input); | ||
var dropDown; | ||
if (this.state.open) { | ||
if (state.open) { | ||
// single and not combobox, input is inside dropdown | ||
@@ -382,3 +414,3 @@ dropDown = <span key="dropdown" className= {joinClasses(prefixCls + '-dropdown', prefixCls + '-dropdown--below')} tabIndex="-1"> | ||
aria-haspopup="true" | ||
aria-expanded={this.state.open} | ||
aria-expanded={state.open} | ||
{...extraSelectionProps} | ||
@@ -399,2 +431,3 @@ > | ||
multiple: React.PropTypes.bool, | ||
tags: React.PropTypes.bool, | ||
onChange: React.PropTypes.func | ||
@@ -401,0 +434,0 @@ }; |
{ | ||
"name": "rc-select", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"description": "select ui component for react", | ||
@@ -40,3 +40,3 @@ "keywords": [ | ||
"start": "node --harmony node_modules/.bin/rc-server", | ||
"publish": "rc-tools run tag && spm publish && spm doc publish", | ||
"publish": "rc-tools run tag && spm publish", | ||
"lint": "rc-tools run lint", | ||
@@ -43,0 +43,0 @@ "test": "", |
@@ -97,4 +97,10 @@ # rc-select | ||
<td>can select more than one option </td> | ||
</tr> | ||
</tr> | ||
<tr> | ||
<td>tags</td> | ||
<td></td> | ||
<td>false</td> | ||
<td>when tagging is enabled the user can select from pre-existing options or create a new tag by picking the first choice, which is what the user has typed into the search box so far.</td> | ||
</tr> | ||
<tr> | ||
<td>allowClear</td> | ||
@@ -101,0 +107,0 @@ <td></td> |
@@ -111,2 +111,6 @@ /** @jsx React.DOM */ | ||
it('should close on blur', function (done) { | ||
if (navigator.userAgent.indexOf(' Chrome') === -1) { | ||
done(); | ||
return; | ||
} | ||
expect(React.findDOMNode(instance).className.match(/\brc-select-open\b/)).to.be.ok(); | ||
@@ -119,4 +123,45 @@ div.focus(); | ||
}); | ||
}); | ||
describe('when use option tags', function () { | ||
var div; | ||
this.timeout(400000); | ||
beforeEach(function () { | ||
div = document.createElement('div'); | ||
div.tabIndex = 0; | ||
document.body.appendChild(div); | ||
instance = React.render( | ||
<Select tags> | ||
<Option value="1">1</Option> | ||
<Option value="2">2</Option> | ||
</Select>, | ||
div); | ||
}); | ||
afterEach(function () { | ||
React.unmountComponentAtNode(div); | ||
}); | ||
it('should allow user input as tags', function (done) { | ||
if (navigator.userAgent.indexOf(' Chrome') === -1) { | ||
done(); | ||
return; | ||
} | ||
var node = React.findDOMNode(instance.refs.input); | ||
React.addons.TestUtils.Simulate.keyDown( node, {key:"A"} ) | ||
setTimeout(function () { | ||
React.addons.TestUtils.Simulate.keyDown( node, {key:"Enter"} ) | ||
setTimeout(function () { | ||
expect(instance.state.value).to.contain("A"); | ||
}, 100); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
37046
8.85%25
4.17%843
10.63%182
3.41%