react-select-module
Version:
A Select control built with and for ReactJS
129 lines (121 loc) • 3.65 kB
JavaScript
import React, { Component } from 'react';
import { cleanValue } from './utils';
import manageState from './stateManager';
import Select from './Select';
const compareOption = (inputValue = '', option) => {
const candidate = String(inputValue).toLowerCase();
const optionValue = String(option.value).toLowerCase();
const optionLabel = String(option.label).toLowerCase();
return optionValue === candidate || optionLabel === candidate;
};
const builtins = {
formatCreateLabel: inputValue => `Create "${inputValue}"`,
isValidNewOption: (inputValue, selectValue, selectOptions) =>
!(
!inputValue ||
selectValue.some(option => compareOption(inputValue, option)) ||
selectOptions.some(option => compareOption(inputValue, option))
),
getNewOptionData: (inputValue, optionLabel) => ({
label: optionLabel,
value: inputValue,
__isNew__: true,
}),
};
export const defaultProps = {
allowCreateWhileLoading: false,
createOptionPosition: 'last',
...builtins,
};
export const makeCreatableSelect = SelectComponent =>
class Creatable extends Component {
static defaultProps = defaultProps;
select;
constructor(props) {
super(props);
const options = props.options || [];
this.state = {
newOption: undefined,
options: options,
};
}
UNSAFE_componentWillReceiveProps(nextProps) {
const {
allowCreateWhileLoading,
createOptionPosition,
formatCreateLabel,
getNewOptionData,
inputValue,
isLoading,
isValidNewOption,
value,
} = nextProps;
const options = nextProps.options || [];
let { newOption } = this.state;
if (isValidNewOption(inputValue, cleanValue(value), options)) {
newOption = getNewOptionData(inputValue, formatCreateLabel(inputValue));
} else {
newOption = undefined;
}
this.setState({
newOption: newOption,
options:
(allowCreateWhileLoading || !isLoading) && newOption
? createOptionPosition === 'first'
? [newOption, ...options]
: [...options, newOption]
: options,
});
}
onChange = (newValue, actionMeta) => {
const {
getNewOptionData,
inputValue,
isMulti,
onChange,
onCreateOption,
value,
name,
} = this.props;
if (actionMeta.action !== 'select-option') {
return onChange(newValue, actionMeta);
}
const { newOption } = this.state;
const valueArray = Array.isArray(newValue) ? newValue : [newValue];
if (valueArray[valueArray.length - 1] === newOption) {
if (onCreateOption) onCreateOption(inputValue);
else {
const newOptionData = getNewOptionData(inputValue, inputValue);
const newActionMeta = { action: 'create-option', name };
if (isMulti) {
onChange([...cleanValue(value), newOptionData], newActionMeta);
} else {
onChange(newOptionData, newActionMeta);
}
}
return;
}
onChange(newValue, actionMeta);
};
focus() {
this.select.focus();
}
blur() {
this.select.blur();
}
render() {
const { options } = this.state;
return (
<SelectComponent
{...this.props}
ref={ref => {
this.select = ref;
}}
options={options}
onChange={this.onChange}
/>
);
}
};
const SelectCreatable = makeCreatableSelect(Select);
export default manageState(SelectCreatable);