react-select-search
Advanced tools
Comparing version 0.9.5 to 0.9.6
@@ -1,35 +0,238 @@ | ||
import test from 'ava'; | ||
import React from 'react'; | ||
import { mount } from 'enzyme'; | ||
import Enzyme, { mount, shallow } from 'enzyme'; | ||
import SelectSearch from '../src'; | ||
import { countries, fontStacks, friends } from './data'; | ||
import './helpers/setup-enzyme'; | ||
import Adapter from 'enzyme-adapter-react-16'; | ||
const options = [{ name: 'Sweden', value: 'SE' }, { name: 'Italy', value: 'IT' }]; | ||
test('has search field', (t) => { | ||
const component = mount(<SelectSearch name="country" options={options} value="SE" />); | ||
const renderFriend = (option) => (<span><img alt="" width="40" height="40" src={option.photo} /><span>{option.name}</span></span>); | ||
t.is(component.find('.select-search-box__search').length, 1); | ||
describe('Full render no-multiple select with search field', () => { | ||
const component = mount(<SelectSearch name="country" options={countries} value="SE" />); | ||
test('has search field', () => { | ||
expect(component.find('.select-search-box__search')).toHaveLength(1); | ||
}); | ||
test('default selected must be Sweden', () => { | ||
expect(component.find('.select-search-box__search').props().value).toBe('Sweden'); | ||
}); | ||
test('displays options on focus', () => { | ||
component.find('.select-search-box__search').simulate('focus'); | ||
expect(component.find('.select-search-box__option')).toHaveLength(243); | ||
}); | ||
test('search field on focus should be empty', () => { | ||
expect(component.find('.select-search-box__search').props().value).toBe(''); | ||
}); | ||
const search = 'Ital'; | ||
test('empties search field on focus', () => { | ||
component.find('.select-search-box__search').simulate('change', { target: { value: search } }); | ||
expect(component.find('.select-search-box__option')).toHaveLength(2); | ||
}); | ||
test('not empty search field after change', () => { | ||
expect(component.find('.select-search-box__search').props().value).toBe(search); | ||
}); | ||
test('select another option', () => { | ||
component.find('.select-search-box__search').simulate('blur').simulate('focus'); | ||
component.find('.select-search-box__option[data-value="BH"]').simulate('click'); | ||
expect(component.find('.select-search-box__search').props().value).toBe('Bahrain'); | ||
}); | ||
}); | ||
test('displays options on focus', (t) => { | ||
const component = mount(<SelectSearch name="country" options={options} value="SE" />); | ||
component.find('.select-search-box__search').simulate('focus'); | ||
describe('Full render multiselect with search field', () => { | ||
const component = mount( | ||
<SelectSearch | ||
name="friends" | ||
multiple | ||
value={['tiffany.gonzales', 'rudolf.wilson']} | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
t.is(component.find('.select-search-box__option').length, 2); | ||
test('input field must be empty', () => { | ||
component.find('.select-search-box__search').simulate('focus'); | ||
expect(component.find('.select-search-box__search').props().value).toBe(''); | ||
}); | ||
test('must have default 2 selected items', () => { | ||
expect(component.find('.select-search-box__option--selected')).toHaveLength(2); | ||
}); | ||
test('selecting item by click', () => { | ||
component.find('.select-search-box__option:not(.select-search-box__option--selected)').first().simulate('click'); | ||
expect(component.find('.select-search-box__option--selected')).toHaveLength(3); | ||
}); | ||
test('unselecting item by click', () => { | ||
component.find('.select-search-box__option--selected').first().simulate('click'); | ||
expect(component.find('.select-search-box__option--selected')).toHaveLength(2); | ||
}); | ||
}); | ||
test('empties search field on focus', (t) => { | ||
const component = mount(<SelectSearch name="country" options={options} value="SE" />); | ||
const search = 'Italy'; | ||
t.is(component.find('.select-search-box__search').props().value, 'Sweden'); | ||
describe('Full render multiselect without search field', () => { | ||
const component = mount( | ||
<SelectSearch | ||
multiple | ||
search={false} | ||
value={['tiffany.gonzales', 'rudolf.wilson', 'emerald.hensley']} | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
component.find('.select-search-box__search').simulate('focus'); | ||
test('input field must be disabled', () => { | ||
expect(component.find('.select-search-box__search')).toHaveLength(0); | ||
}); | ||
t.is(component.find('.select-search-box__search').props().value, ''); | ||
test('must have default 3 selected items', () => { | ||
expect(component.find('.select-search-box__option--selected')).toHaveLength(3); | ||
}); | ||
component.find('.select-search-box__search').simulate('change', { target: { value: search } }); | ||
}); | ||
t.is(component.find('.select-search-box__search').props().value, search); | ||
describe('Full render no-multiple select without search field and with empty value', () => { | ||
const component = mount( | ||
<SelectSearch | ||
search={false} | ||
value='' | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
test('with empty .values', () => { | ||
expect(component.find('.select-search-box__search--placeholder').text()).toBe(''); | ||
}); | ||
}); | ||
describe('Full render multiselect without search field and with empty value', () => { | ||
const component = mount( | ||
<SelectSearch | ||
multiple | ||
search={false} | ||
value='' | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
test('with empty state.values', () => { | ||
expect(component.find('.select-search-box__out>option').text()).toBe('Nothing selected'); | ||
}); | ||
}); | ||
describe('Group tests', () => { | ||
const component = mount( | ||
<SelectSearch | ||
value='Playfair Display' | ||
options={fontStacks} | ||
/> | ||
); | ||
test('must have one grouped option with two sub-options', () => { | ||
expect(component.find('.select-search-box__group-header')).toHaveLength(4); | ||
expect(component.find('.select-search-box__option')).toHaveLength(5); | ||
}); | ||
}); | ||
describe('Unit tests', () => { | ||
Enzyme.configure({ | ||
adapter: new Adapter(), | ||
disableLifecycleMethods: true | ||
}); | ||
let input; | ||
const renderFriend = (option) => (<span><span>{option.name}</span></span>); | ||
test('set the state.search changes search field immediately', () => { | ||
class Component extends React.Component { | ||
render() { | ||
return ( | ||
<SelectSearch | ||
multiple | ||
value={['tiffany.gonzales', 'rudolf.wilson']} | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
} | ||
} | ||
const component = shallow(<Component />); | ||
const cmpInstance = component.dive().dive().instance(); | ||
return new Promise((resolve) => { | ||
cmpInstance.setState({ search: 'ti' }, resolve); | ||
}).then(() => { | ||
input = cmpInstance.renderSearchField(); | ||
expect(input.props.value).toBe('ti'); | ||
}); | ||
}); | ||
test('renderSearchField function. Multiple with search field', () => { | ||
class Component extends React.Component { | ||
render() { | ||
return ( | ||
<SelectSearch | ||
multiple | ||
search={false} | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
} | ||
} | ||
const component = shallow(<Component />); | ||
const cmpInstance = component.dive().dive().instance(); | ||
input = cmpInstance.renderSearchField(); | ||
expect(input).toBeUndefined(); | ||
}); | ||
test('renderSearchField function. Drop down list without search field in default must contain a default element text', () => { | ||
class Component extends React.Component { | ||
render() { | ||
return ( | ||
<SelectSearch | ||
search={false} | ||
value='tiffany.gonzales' | ||
options={friends} | ||
renderOption={renderFriend} | ||
/> | ||
); | ||
} | ||
} | ||
const component = shallow(<Component />); | ||
const cmpInstanceForProps = component.dive().dive() | ||
const cmpInstance = cmpInstanceForProps.instance(); | ||
cmpInstanceForProps.setProps({ search: false }); | ||
input = cmpInstance.renderSearchField(); | ||
expect(shallow(input).text()).toBe('Tiffany Gonzales'); | ||
}); | ||
}); |
@@ -5,45 +5,4 @@ import React from 'react'; | ||
import '../style.css'; | ||
import { countries, fontStacks, friends, colors } from './data'; | ||
const fontStacks = [ | ||
{ | ||
type: 'group', | ||
name: 'Sans serif', | ||
items: [ | ||
{ name: 'Roboto', value: 'Roboto', 'data-stack': 'Roboto, sans-serif' }, | ||
], | ||
}, | ||
{ | ||
type: 'group', | ||
name: 'Serif', | ||
items: [ | ||
{ name: 'Playfair Display', value: 'Playfair Display', 'data-stack': '"Playfair Display", serif' }, | ||
], | ||
}, | ||
{ | ||
type: 'group', | ||
name: 'Cursive', | ||
items: [ | ||
{ name: 'Monoton', value: 'Monoton', 'data-stack': 'Monoton, cursive' }, | ||
{ name: 'Gloria Hallelujah', value: 'Gloria Hallelujah', 'data-stack': '"Gloria Hallelujah", cursive' }, | ||
], | ||
}, | ||
{ | ||
type: 'group', | ||
name: 'Monospace', | ||
items: [ | ||
{ name: 'VT323', value: 'VT323', 'data-stack': 'VT323, monospace' }, | ||
], | ||
}, | ||
]; | ||
// https://randomuser.me/ | ||
const friends = [ | ||
{ name: 'Annie Cruz', value: 'annie.cruz', photo: 'https://randomuser.me/api/portraits/women/60.jpg' }, | ||
{ name: 'Eli Shelton', value: 'eli.shelton', photo: 'https://randomuser.me/api/portraits/men/7.jpg' }, | ||
{ name: 'Loretta Rogers', value: 'loretta.rogers', photo: 'https://randomuser.me/api/portraits/women/51.jpg' }, | ||
{ name: 'Lloyd Fisher', value: 'lloyd.fisher', photo: 'https://randomuser.me/api/portraits/men/34.jpg' }, | ||
{ name: 'Tiffany Gonzales', value: 'tiffany.gonzales', photo: 'https://randomuser.me/api/portraits/women/71.jpg' }, | ||
]; | ||
/** https://gist.github.com/Keeguon/2310008 */ | ||
const countryOptions = require('./data/countries'); | ||
function renderFontValue(label, option) { | ||
@@ -79,2 +38,6 @@ if (!option) { | ||
function renderColors(option) { | ||
return (<span><span>{option.name}</span></span>); | ||
} | ||
class App extends React.Component { | ||
@@ -84,3 +47,4 @@ state = { | ||
country: 'SE', | ||
friends: '', | ||
friends: [], | ||
colors: ['red', 'purple'] | ||
}; | ||
@@ -92,3 +56,4 @@ | ||
country: '', | ||
friends: '', | ||
friends: [], | ||
colors: [] | ||
}); | ||
@@ -114,3 +79,3 @@ }; | ||
value={this.state.country} | ||
options={countryOptions} | ||
options={countries} | ||
placeholder="Your country" | ||
@@ -121,3 +86,3 @@ /> | ||
multiple | ||
value={this.state.friends} | ||
value={this.state.friends_search} | ||
height={172} | ||
@@ -128,2 +93,11 @@ options={friends} | ||
/> | ||
<SelectSearch | ||
name="colors" | ||
multiple | ||
search={false} | ||
value={this.state.colors} | ||
height={172} | ||
options={colors} | ||
renderOption={renderColors} | ||
/> | ||
</div> | ||
@@ -130,0 +104,0 @@ ); |
@@ -10,3 +10,3 @@ const { resolve, join } = require('path'); | ||
filename: 'index.js', | ||
publicPath: '/static/' | ||
publicPath: '/', | ||
}, | ||
@@ -13,0 +13,0 @@ resolve: { |
{ | ||
"name": "react-select-search", | ||
"version": "0.9.5", | ||
"version": "0.9.6", | ||
"description": "React powered selectbox with filter", | ||
@@ -8,3 +8,6 @@ "main": "dist/index.js", | ||
"lint": "eslint src/index.js", | ||
"test": "ava", | ||
"test": "jest", | ||
"test:watch": "yarn test --watch", | ||
"test:coverage": "yarn test --coverage", | ||
"coveralls": "yarn test:coverage && cat ./coverage/lcov.info | coveralls", | ||
"dev": "webpack-dev-server --config example/webpack.config.js", | ||
@@ -31,4 +34,4 @@ "build": "NODE_ENV=production babel src --out-dir dist" | ||
"peerDependencies": { | ||
"react": "^16.4.2", | ||
"react-dom": "^16.4.2" | ||
"react": "^16.8.1", | ||
"react-dom": "^16.8.1" | ||
}, | ||
@@ -43,3 +46,2 @@ "devDependencies": { | ||
"@babel/register": "^7.0.0-beta.40", | ||
"ava": "^1.0.1", | ||
"babel-eslint": "^8.2.1", | ||
@@ -49,5 +51,6 @@ "babel-loader": "^8.0.0-beta.0", | ||
"browser-env": "^3.2.5", | ||
"coveralls": "^3.0.2", | ||
"css-loader": "^0.28.9", | ||
"enzyme": "^3.3.0", | ||
"enzyme-adapter-react-16": "^1.1.1", | ||
"enzyme": "^3.8.0", | ||
"enzyme-adapter-react-16": "^1.9.1", | ||
"eslint": "^4.11.0", | ||
@@ -62,3 +65,4 @@ "eslint-config-airbnb": "^16.1.0", | ||
"html-webpack-plugin": "^2.30.1", | ||
"prop-types": "^15.6.1", | ||
"jest": "^24.1.0", | ||
"prop-types": "^15.6.2", | ||
"style-loader": "^0.20.1", | ||
@@ -68,9 +72,2 @@ "webpack": "^3.10.0", | ||
}, | ||
"ava": { | ||
"require": [ | ||
"@babel/register", | ||
"./__tests__/helpers/setup-browser-env.js", | ||
"./__tests__/helpers/setup-enzyme.js" | ||
] | ||
}, | ||
"dependencies": { | ||
@@ -77,0 +74,0 @@ "fuse.js": "^3.2.0", |
@@ -9,2 +9,5 @@ <p align="center"> | ||
</a> | ||
<a href='https://coveralls.io/github/tbleckert/react-select-search?branch=master'> | ||
<img src='https://coveralls.io/repos/github/tbleckert/react-select-search/badge.svg?branch=master' alt='Coverage Status' /> | ||
</a> | ||
<a href="https://www.npmjs.com/package/react-select-search"> | ||
@@ -11,0 +14,0 @@ <img src="https://img.shields.io/badge/license-MIT-blue.svg" style="max-width:100%;" /> |
@@ -9,3 +9,3 @@ import React from 'react'; | ||
class SelectSearch extends React.Component { | ||
class SelectSearch extends React.PureComponent { | ||
static defaultProps = { | ||
@@ -40,3 +40,3 @@ className: 'select-search-box', | ||
const { options, value, multiple } = props; | ||
const { options, value, multiple, className } = props; | ||
const stateValue = (!value && multiple) ? [] : value; | ||
@@ -65,17 +65,23 @@ const flattenedOptions = FlattenOptions(options); | ||
this.classes = { | ||
container: (this.props.multiple) ? `${this.props.className} ${Bem.m(this.props.className, 'multiple')}` : this.props.className, | ||
search: Bem.e(this.props.className, 'search'), | ||
select: Bem.e(this.props.className, 'select'), | ||
options: Bem.e(this.props.className, 'options'), | ||
option: Bem.e(this.props.className, 'option'), | ||
row: Bem.e(this.props.className, 'row'), | ||
group: Bem.e(this.props.className, 'group'), | ||
groupHeader: Bem.e(this.props.className, 'group-header'), | ||
out: Bem.e(this.props.className, 'out'), | ||
label: Bem.e(this.props.className, 'label'), | ||
focus: (this.props.multiple) ? `${this.props.className} ${Bem.m(this.props.className, 'multiple focus')}` : `${this.props.className} ${Bem.m(this.props.className, 'focus')}`, | ||
container: (multiple) ? `${className} ${Bem.m(className, 'multiple')}` : className, | ||
search: Bem.e(className, 'search'), | ||
select: Bem.e(className, 'select'), | ||
options: Bem.e(className, 'options'), | ||
option: Bem.e(className, 'option'), | ||
row: Bem.e(className, 'row'), | ||
group: Bem.e(className, 'group'), | ||
groupHeader: Bem.e(className, 'group-header'), | ||
out: Bem.e(className, 'out'), | ||
label: Bem.e(className, 'label'), | ||
focus: (multiple) ? `${className} ${Bem.m(className, 'multiple focus')}` : `${className} ${Bem.m(className, 'focus')}`, | ||
}; | ||
this.classes.focus += ` ${Bem.m(this.props.className, 'select')}`; | ||
this.classes.container += ` ${Bem.m(this.props.className, 'select')}`; | ||
if (multiple && !this.props.search) { | ||
this.classes.container += ` ${Bem.m(Bem.e(className, 'icon'), 'disabled')}`; | ||
} | ||
if (!this.props.search) { | ||
this.classes.focus += ` ${Bem.m(Bem.e(className, 'icon'), 'disabled')}`; | ||
} | ||
this.classes.container += ` ${Bem.m(className, 'select')}`; | ||
this.classes.focus += ` ${Bem.m(className, 'select')}`; | ||
@@ -360,3 +366,3 @@ this.container = React.createRef(); | ||
chooseOption(value) { | ||
let currentValue = this.state.value; | ||
let currentValue = this.state.value.slice(); | ||
let option; | ||
@@ -381,5 +387,6 @@ let search; | ||
} | ||
const currentIndex = currentValue.indexOf(option.value); | ||
currentIndex > -1 ? currentValue.splice(currentIndex, 1) : currentValue.push(option.value); | ||
currentValue.push(option.value); | ||
search = ''; | ||
@@ -418,3 +425,3 @@ } else { | ||
const option = this.findByValue(this.state.defaultOptions, value); | ||
const optionValue = this.state.value; | ||
const optionValue = this.state.value.slice(); | ||
@@ -573,3 +580,3 @@ if (!option || optionValue.indexOf(option.value) < 0) { | ||
if (this.props.multiple) { | ||
if (this.state.value) { | ||
if (Object.prototype.toString.call(this.state.value) == '[object Array]' && this.state.value.length) { | ||
const finalValueOptions = []; | ||
@@ -626,2 +633,6 @@ | ||
} else { | ||
if (this.props.multiple) { | ||
return; | ||
} | ||
let option; | ||
@@ -640,3 +651,3 @@ let labelValue; | ||
} | ||
labelValue = option.name; | ||
@@ -643,0 +654,0 @@ labelClassName = this.classes.search; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
37
2554
126
403687
29