Skip to content
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ React.render(c, container);
|value | current selected option(s) | String/Array<String>/{key:String, label:React.Node}/Array<{key, label}> | - |
|firstActiveValue | first active value when there is no value | String/Array<String> | - |
|labelInValue| whether to embed label in value, see above value type | Bool | false |
|backfill| whether backfill select option to search input (Only works in single and combobox mode) | Bool | false |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single 模式支持 backfill 感觉没啥意义,只是个展示效果?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只是顺便支持下

|onChange | called when select an option or input value change(combobox) | function(value) | - |
|onSearch | called when input changed | function | - |
|onBlur | called when blur | function | - |
Expand Down
4 changes: 2 additions & 2 deletions examples/combobox.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'rc-select/assets/index.less';
class Demo extends React.Component {
state = {
disabled: false,
value: 'l',
value: '',
};

onChange = (value) => {
Expand Down Expand Up @@ -45,12 +45,12 @@ class Demo extends React.Component {
style={{ width: 500 }}
onChange={this.onChange}
onSelect={this.onSelect}
defaultActiveFirstOption={false}
notFoundContent=""
allowClear
placeholder="please select"
value={this.state.value}
combobox
backfill
>
<Option value="jack">
<b style={{ color: 'red' }}>jack</b>
Expand Down
1 change: 1 addition & 0 deletions examples/single.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Test extends React.Component {
optionFilterProp="text"
onChange={this.onChange}
firstActiveValue="2"
backfill
>
<Option value="01" text="jack" title="jack">
<b
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"dom-scroll-into-view": "1.x",
"prop-types": "^15.5.8",
"rc-animate": "2.x",
"rc-menu": "5.x || 4.x",
"rc-menu": "^5.0.11",
"rc-trigger": "1.x",
"rc-util": "^4.0.4",
"warning": "2.x"
Expand Down
3 changes: 2 additions & 1 deletion src/DropdownMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ export default class DropdownMenu extends React.Component {
}

// clear activeKey when inputValue change
if (inputValue !== this.lastInputValue) {
const lastValue = value && value[value.length - 1];
if (inputValue !== this.lastInputValue && (!lastValue || !lastValue.backfill)) {
activeKeyProps.activeKey = '';
}

Expand Down
32 changes: 29 additions & 3 deletions src/Select.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export default class Select extends React.Component {
optionFilterProp: 'value',
optionLabelProp: 'value',
notFoundContent: 'Not Found',
backfill: false,
};

constructor(props) {
Expand Down Expand Up @@ -237,7 +238,7 @@ export default class Select extends React.Component {

if (state.open) {
const menu = this.refs.trigger.getInnerMenu();
if (menu && menu.onKeyDown(event)) {
if (menu && menu.onKeyDown(event, this.handleBackfill)) {
event.preventDefault();
event.stopPropagation();
}
Expand All @@ -249,6 +250,7 @@ export default class Select extends React.Component {
const props = this.props;
const selectedValue = getValuePropValue(item);
const selectedLabel = this.getLabelFromOption(item);
const lastValue = value[value.length - 1];
let event = selectedValue;
if (props.labelInValue) {
event = {
Expand Down Expand Up @@ -277,7 +279,7 @@ export default class Select extends React.Component {
this.skipAdjustOpen = false;
}, 0);
}
if (value.length && value[0].key === selectedValue) {
if (lastValue && lastValue.key === selectedValue && !lastValue.backfill) {
this.setOpenState(false, true);
return;
}
Expand Down Expand Up @@ -589,8 +591,32 @@ export default class Select extends React.Component {
}
};

handleBackfill = (item) => {
if (!this.props.backfill || !(isSingleMode(this.props) || isCombobox(this.props))) {
return;
}

const key = getValuePropValue(item);
const label = this.getLabelFromOption(item);
const backfillValue = {
key,
label,
backfill: true,
};

if (isCombobox(this.props)) {
this.setInputValue(key, false);
}

this.setState({
value: [backfillValue],
});
};

filterOption = (input, child, defaultFilter = defaultFilterFn) => {
if (!input) {
const { value } = this.state;
const lastValue = value[value.length - 1];
if (!input || (lastValue && lastValue.backfill)) {
return true;
}
let filterFn = this.props.filterOption;
Expand Down
44 changes: 44 additions & 0 deletions tests/Select.combobox.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import React from 'react';
import Select, { Option } from '../src';
import { mount, render } from 'enzyme';
import KeyCode from 'rc-util/lib/KeyCode';
import allowClearTest from './shared/allowClearTest';

const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
Expand Down Expand Up @@ -195,4 +196,47 @@ describe('Select.combobox', () => {
});
});
});

it('backfill', () => {
const handleChange = jest.fn();
const handleSelect = jest.fn();
const wrapper = mount(
<Select
combobox
backfill
open
onChange={handleChange}
onSelect={handleSelect}
>
<Option value="One">One</Option>
<Option value="Two">Two</Option>
</Select>
);

const input = wrapper.find('input');

input.simulate('keyDown', { keyCode: KeyCode.DOWN });

expect(wrapper.state().value).toEqual([
{
key: 'Two',
label: 'Two',
backfill: true,
},
]);
expect(wrapper.state().inputValue).toBe('Two');
expect(handleChange).not.toBeCalled();
expect(handleSelect).not.toBeCalled();

input.simulate('keyDown', { keyCode: KeyCode.ENTER });

expect(wrapper.state().value).toEqual([
{
key: 'Two',
label: 'Two',
},
]);
expect(handleChange).toBeCalledWith('Two');
expect(handleSelect).toBeCalledWith('Two', expect.anything());
});
});
42 changes: 42 additions & 0 deletions tests/Select.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -630,4 +630,46 @@ describe('Select', () => {

expect(wrapper).toMatchSnapshot();
});

it('backfill', () => {
const handleChange = jest.fn();
const handleSelect = jest.fn();
const wrapper = mount(
<Select
backfill
open
onChange={handleChange}
onSelect={handleSelect}
optionLabelProp="children"
>
<Option value="1">One</Option>
<Option value="2">Two</Option>
</Select>
);

const input = wrapper.find('input');

input.simulate('keyDown', { keyCode: KeyCode.DOWN });

expect(wrapper.state().value).toEqual([
{
key: '2',
label: 'Two',
backfill: true,
},
]);
expect(handleChange).not.toBeCalled();
expect(handleSelect).not.toBeCalled();

input.simulate('keyDown', { keyCode: KeyCode.ENTER });

expect(wrapper.state().value).toEqual([
{
key: '2',
label: 'Two',
},
]);
expect(handleChange).toBeCalledWith('2');
expect(handleSelect).toBeCalledWith('2', expect.anything());
});
});