Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

feat(Picky): Support uncontrolled components #20

Merged
merged 4 commits into from
Dec 29, 2017
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
39 changes: 25 additions & 14 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3021,28 +3021,30 @@ var Picky$1 = function (_React$Component) {
}
}, {
key: 'selectValue',
value: function selectValue(value) {
value: function selectValue(val) {
var _this2 = this;

if (this.props.multiple && Array.isArray(this.props.value)) {
if (this.props.value.includes(value)) {
var currIndex = this.props.value.indexOf(value);
var valueLookup = this.isControlled() ? this.props.value : this.state.selectedValue;

if (this.props.multiple && Array.isArray(valueLookup)) {
if (valueLookup.includes(val)) {
var currIndex = valueLookup.indexOf(val);
// Remove
this.setState({
selectedValue: [].concat(_toConsumableArray(this.props.value.slice(0, currIndex)), _toConsumableArray(this.props.value.slice(currIndex + 1)))
selectedValue: [].concat(_toConsumableArray(valueLookup.slice(0, currIndex)), _toConsumableArray(valueLookup.slice(currIndex + 1)))
}, function () {
_this2.props.onChange(_this2.state.selectedValue);
});
} else {
this.setState({
selectedValue: [].concat(_toConsumableArray(this.state.selectedValue), [value])
selectedValue: [].concat(_toConsumableArray(this.state.selectedValue), [val])
}, function () {
_this2.props.onChange(_this2.state.selectedValue);
});
}
} else {
this.setState({
selectedValue: value
selectedValue: val
}, function () {
_this2.props.onChange(_this2.state.selectedValue);
});
Expand Down Expand Up @@ -3070,6 +3072,11 @@ var Picky$1 = function (_React$Component) {
_this3.props.onChange(_this3.state.selectedValue);
});
}
}, {
key: 'isControlled',
value: function isControlled() {
return this.props.value != null;
}
}, {
key: 'renderOptions',
value: function renderOptions() {
Expand Down Expand Up @@ -3098,8 +3105,12 @@ var Picky$1 = function (_React$Component) {

var item = items[index];
var key = isDataObject(item, labelKey, valueKey) ? item[valueKey] : item;

var isSelected = Array.isArray(value) && value.includes(item) || !Array.isArray(value) && value === item;
var isSelected = false;
if (_this4.isControlled()) {
isSelected = Array.isArray(value) && value.includes(item) || !Array.isArray(value) && value === item;
} else {
isSelected = Array.isArray(_this4.state.selectedValue) && _this4.state.selectedValue.includes(item) || !Array.isArray(_this4.state.selectedValue) && _this4.state.selectedValue === item;
}

if (typeof _this4.props.render === 'function') {
return _this4.props.render({
Expand Down Expand Up @@ -3130,20 +3141,20 @@ var Picky$1 = function (_React$Component) {
}
}, {
key: 'onFilterChange',
value: function onFilterChange(value) {
value: function onFilterChange(term) {
var _this5 = this;

if (!value.trim()) {
if (!term.trim()) {
return this.setState({
filtered: false,
filteredOptions: []
});
}
var filteredOptions = this.props.options.filter(function (option) {
if (isDataObject(option, _this5.props.labelKey, _this5.props.valueKey)) {
return String(option[_this5.props.labelKey]).toLowerCase().includes(value.toLowerCase());
return String(option[_this5.props.labelKey]).toLowerCase().includes(term.toLowerCase());
}
return String(option).toLowerCase().includes(value.toLowerCase());
return String(option).toLowerCase().includes(term.toLowerCase());
});
this.setState({
filtered: true,
Expand Down Expand Up @@ -3212,7 +3223,7 @@ var Picky$1 = function (_React$Component) {
},
React__default.createElement(Placeholder, {
placeholder: placeholder,
value: value,
value: this.isControlled() ? value : this.state.selectedValue,
multiple: multiple,
numberDisplayed: numberDisplayed,
valueKey: valueKey,
Expand Down
49 changes: 32 additions & 17 deletions src/Picky.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,20 @@ class Picky extends React.Component {
}
}

selectValue(value) {
if (this.props.multiple && Array.isArray(this.props.value)) {
if (this.props.value.includes(value)) {
const currIndex = this.props.value.indexOf(value);
selectValue(val) {
const valueLookup = this.isControlled()
? this.props.value
: this.state.selectedValue;

if (this.props.multiple && Array.isArray(valueLookup)) {
if (valueLookup.includes(val)) {
const currIndex = valueLookup.indexOf(val);
// Remove
this.setState(
{
selectedValue: [
...this.props.value.slice(0, currIndex),
...this.props.value.slice(currIndex + 1)
...valueLookup.slice(0, currIndex),
...valueLookup.slice(currIndex + 1)
]
},
() => {
Expand All @@ -64,7 +68,7 @@ class Picky extends React.Component {
} else {
this.setState(
{
selectedValue: [...this.state.selectedValue, value]
selectedValue: [...this.state.selectedValue, val]
},
() => {
this.props.onChange(this.state.selectedValue);
Expand All @@ -74,7 +78,7 @@ class Picky extends React.Component {
} else {
this.setState(
{
selectedValue: value
selectedValue: val
},
() => {
this.props.onChange(this.state.selectedValue);
Expand Down Expand Up @@ -102,6 +106,9 @@ class Picky extends React.Component {
}
);
}
isControlled() {
return this.props.value != null;
}

renderOptions() {
const {
Expand All @@ -127,10 +134,18 @@ class Picky extends React.Component {
const key = isDataObject(item, labelKey, valueKey)
? item[valueKey]
: item;

const isSelected =
(Array.isArray(value) && value.includes(item)) ||
(!Array.isArray(value) && value === item);
let isSelected = false;
if (this.isControlled()) {
isSelected =
(Array.isArray(value) && value.includes(item)) ||
(!Array.isArray(value) && value === item);
} else {
isSelected =
(Array.isArray(this.state.selectedValue) &&
this.state.selectedValue.includes(item)) ||
(!Array.isArray(this.state.selectedValue) &&
this.state.selectedValue === item);
}

if (typeof this.props.render === 'function') {
return this.props.render({
Expand Down Expand Up @@ -162,8 +177,8 @@ class Picky extends React.Component {
/>
);
}
onFilterChange(value) {
if (!value.trim()) {
onFilterChange(term) {
if (!term.trim()) {
return this.setState({
filtered: false,
filteredOptions: []
Expand All @@ -173,11 +188,11 @@ class Picky extends React.Component {
if (isDataObject(option, this.props.labelKey, this.props.valueKey)) {
return String(option[this.props.labelKey])
.toLowerCase()
.includes(value.toLowerCase());
.includes(term.toLowerCase());
}
return String(option)
.toLowerCase()
.includes(value.toLowerCase());
.includes(term.toLowerCase());
});
this.setState(
{
Expand Down Expand Up @@ -243,7 +258,7 @@ class Picky extends React.Component {
>
<Placeholder
placeholder={placeholder}
value={value}
value={this.isControlled() ? value : this.state.selectedValue}
multiple={multiple}
numberDisplayed={numberDisplayed}
valueKey={valueKey}
Expand Down
37 changes: 35 additions & 2 deletions tests/Picky.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ describe('Picky', () => {
expect(onChange).toHaveBeenCalledWith([1, 2, 3, 4, 5]);
});

it('should select single value', () => {
it('should select single value controlled', () => {
const onChange = jest.fn();
const wrapper = mount(
<Picky
Expand All @@ -172,7 +172,20 @@ describe('Picky', () => {
.simulate('click');
expect(onChange).lastCalledWith(2);
});
it('should select multiple value', () => {

it('should select single value uncontrolled', () => {
const onChange = jest.fn();
const wrapper = mount(
<Picky options={[1, 2, 3, 4, 5]} open={true} onChange={onChange} />
);
expect(wrapper.state('selectedValue')).toEqual(null);
wrapper
.find('.picky__dropdown .option')
.at(1)
.simulate('click');
expect(onChange).lastCalledWith(2);
});
it('should select multiple value controlled', () => {
const onChange = jest.fn();
const wrapper = mount(
<Picky
Expand All @@ -192,6 +205,26 @@ describe('Picky', () => {
expect(onChange).lastCalledWith([2]);
expect(wrapper.state('selectedValue')).toEqual([2]);
});
it('should select multiple value uncontrolled', () => {
const onChange = jest.fn();
const wrapper = mount(
<Picky
options={[1, 2, 3, 4, 5]}
open={true}
multiple
onChange={onChange}
/>
);

expect(wrapper.state('selectedValue')).toEqual([]);
wrapper
.find('.picky__dropdown .option')
.at(1)
.simulate('click');
expect(onChange).lastCalledWith([2]);
expect(wrapper.state('selectedValue')).toEqual([2]);
});

it('should deselect multiple value', () => {
const onChange = jest.fn();
const wrapper = mount(
Expand Down