Skip to content

Commit

Permalink
Merge branch 'master' into fix-1437-creatable-no-focus
Browse files Browse the repository at this point in the history
  • Loading branch information
the-spyke committed Mar 30, 2017
2 parents 5513893 + 5f7c4c6 commit c3e9f46
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 107 deletions.
211 changes: 105 additions & 106 deletions README.md
Expand Up @@ -78,19 +78,19 @@ When the value is changed, `onChange(selectedValueOrValues)` will fire.
var Select = require('react-select');

var options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
];

function logChange(val) {
console.log("Selected: " + val);
console.log("Selected: " + val);
}

<Select
name="form-field-name"
value="one"
options={options}
onChange={logChange}
name="form-field-name"
value="one"
options={options}
onChange={logChange}
/>
```

Expand All @@ -113,8 +113,8 @@ You can enable multi-value selection by setting `multi={true}`. In this mode:
* By default, selected options can be cleared. To disable the possibility of clearing a particular option, add `clearableValue: false` to that option:
```javascript
var options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two', clearableValue: false }
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two', clearableValue: false }
];
```
Note: the `clearable` prop of the Select component should also be set to `false` to prevent allowing clearing all fields at once
Expand All @@ -135,17 +135,17 @@ Unless you specify the property `autoload={false}` the control will automaticall
var Select = require('react-select');

var getOptions = function(input, callback) {
setTimeout(function() {
callback(null, {
options: [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
],
// CAREFUL! Only set this to true when there are no more options,
// or more specific queries will not be sent to the server.
complete: true
});
}, 500);
setTimeout(function() {
callback(null, {
options: [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
],
// CAREFUL! Only set this to true when there are no more options,
// or more specific queries will not be sent to the server.
complete: true
});
}, 500);
};

<Select.Async
Expand All @@ -168,8 +168,8 @@ import Select from 'react-select';
/*
* assuming the API returns something like this:
* const json = [
* { value: 'one', label: 'One' },
* { value: 'two', label: 'Two' }
* { value: 'one', label: 'One' },
* { value: 'two', label: 'Two' }
* ]
*/

Expand All @@ -183,9 +183,9 @@ const getOptions = (input) => {
}

<Select.Async
name="form-field-name"
value="one"
loadOptions={getOptions}
name="form-field-name"
value="one"
loadOptions={getOptions}
/>
```

Expand All @@ -200,8 +200,8 @@ var isLoadingExternally = true;

<Select
name="form-field-name"
isLoading={isLoadingExternally}
...
isLoading={isLoadingExternally}
...
/>
```

Expand All @@ -221,15 +221,15 @@ function render (selectProps) {

##### Creatable properties

Property | Type | Description
| Property | Type | Description
:---|:---|:---
`children` | function | Child function responsible for creating the inner Select component. This component can be used to compose HOCs (eg Creatable and Async). Expected signature: `(props: Object): PropTypes.element` |
`isOptionUnique` | function | Searches for any matching option within the set of options. This function prevents duplicate options from being created. By default this is a basic, case-sensitive comparison of label and value. Expected signature: `({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean` |
`isValidNewOption` | function | Determines if the current input text represents a valid option. By default any non-empty string will be considered valid. Expected signature: `({ label: string }): boolean` |
`newOptionCreator` | function | Factory to create new option. Expected signature: `({ label: string, labelKey: string, valueKey: string }): Object` |
`onNewOptionClick` | function | new option click handler, it calls when new option has been selected. `function(option) {}` |
`shouldKeyDownEventCreateNewOption` | function | Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. ENTER, TAB and comma keys create new options by default. Expected signature: `({ keyCode: number }): boolean` |
`promptTextCreator` | function | Factory for overriding default option creator prompt label. By default it will read 'Create option "{label}"'. Expected signature: `(label: String): String` |
| `children` | function | Child function responsible for creating the inner Select component. This component can be used to compose HOCs (eg Creatable and Async). Expected signature: `(props: Object): PropTypes.element` |
| `isOptionUnique` | function | Searches for any matching option within the set of options. This function prevents duplicate options from being created. By default this is a basic, case-sensitive comparison of label and value. Expected signature: `({ option: Object, options: Array, labelKey: string, valueKey: string }): boolean` |
| `isValidNewOption` | function | Determines if the current input text represents a valid option. By default any non-empty string will be considered valid. Expected signature: `({ label: string }): boolean` |
| `newOptionCreator` | function | Factory to create new option. Expected signature: `({ label: string, labelKey: string, valueKey: string }): Object` |
| `onNewOptionClick` | function | new option click handler, it calls when new option has been selected. `function(option) {}` |
| `shouldKeyDownEventCreateNewOption` | function | Decides if a keyDown event (eg its `keyCode`) should result in the creation of a new option. ENTER, TAB and comma keys create new options by default. Expected signature: `({ keyCode: number }): boolean` |
| `promptTextCreator` | function | Factory for overriding default option creator prompt label. By default it will read 'Create option "{label}"'. Expected signature: `(label: String): String` |

### Combining Async and Creatable

Expand Down Expand Up @@ -307,7 +307,7 @@ You can manipulate the input using the onInputChange and returning a new value.

```js
function cleanInput(inputValue) {
// Strip all non-number characters from the input
// Strip all non-number characters from the input
return inputValue.replace(/[^0-9]/g, "");
}

Expand All @@ -324,84 +324,83 @@ You can extend or override this behavior by providing a `onInputKeyDown` callbac

```js
function onInputKeyDown(event) {
switch (event.keyCode) {
case 9: // TAB
// Extend default TAB behavior by doing something here
break;
case 13: // ENTER
// Override default ENTER behavior by doing stuff here and then preventing default
event.preventDefault();
break;
}
switch (event.keyCode) {
case 9: // TAB
// Extend default TAB behavior by doing something here
break;
case 13: // ENTER
// Override default ENTER behavior by doing stuff here and then preventing default
event.preventDefault();
break;
}
}

<Select
{...otherProps}
onInputKeyDown={onInputKeyDown}
{...otherProps}
onInputKeyDown={onInputKeyDown}
/>
```

### Further options


Property | Type | Default | Description
:-----------------------|:--------------|:--------------|:--------------------------------
addLabelText | string | 'Add "{label}"?' | text to display when `allowCreate` is true
arrowRenderer | func | undefined | Renders a custom drop-down arrow to be shown in the right-hand side of the select: `arrowRenderer({ onMouseDown, isOpen })`
autoBlur | bool | false | Blurs the input element after a selection has been made. Handy for lowering the keyboard on mobile devices
autofocus | bool | undefined | autofocus the component on mount
autoload | bool | true | whether to auto-load the default async options set
autosize | bool | true | If enabled, the input will expand as the length of its value increases
backspaceRemoves | bool | true | whether pressing backspace removes the last item when there is no input value
backspaceToRemoveMessage | string | 'Press backspace to remove {last label}' | prompt shown in input when at least one option in a multiselect is shown, set to '' to clear
cache | bool | true | enables the options cache for `asyncOptions` (default: `true`)
className | string | undefined | className for the outer element
clearable | bool | true | should it be possible to reset value
clearAllText | string | 'Clear all' | title for the "clear" control when `multi` is true
clearRenderer | func | undefined | Renders a custom clear to be shown in the right-hand side of the select when clearable true: `clearRenderer()`
clearValueText | string | 'Clear value' | title for the "clear" control
resetValue | any | null | value to use when you clear the control
deleteRemoves | bool | true | whether pressing delete key removes the last item when there is no input value
delimiter | string | ',' | delimiter to use to join multiple values
disabled | bool | false | whether the Select is disabled or not
filterOption | func | undefined | method to filter a single option: `function(option, filterString)`
filterOptions | func | undefined | method to filter the options array: `function([options], filterString, [values])`
ignoreAccents | bool | true | whether to strip accents when filtering
ignoreCase | bool | true | whether to perform case-insensitive filtering
inputProps | object | {} | custom attributes for the Input (in the Select-control) e.g: `{'data-foo': 'bar'}`
isLoading | bool | false | whether the Select is loading externally or not (such as options being loaded)
joinValues | bool | false | join multiple values into a single hidden input using the `delimiter`
labelKey | string | 'label' | the option property to use for the label
loadOptions | func | undefined | function that returns a promise or calls a callback with the options: `function(input, [callback])`
matchPos | string | 'any' | (any, start) match the start or entire string when filtering
matchProp | string | 'any' | (any, label, value) which option property to filter on
menuBuffer | number | 0 | buffer of px between the base of the dropdown and the viewport to shift if menu doesnt fit in viewport
menuRenderer | func | undefined | Renders a custom menu with options; accepts the following named parameters: `menuRenderer({ focusedOption, focusOption, options, selectValue, valueArray })`
multi | bool | undefined | multi-value input
name | string | undefined | field name, for hidden `<input />` tag
noResultsText | string | 'No results found' | placeholder displayed when there are no matching search results or a falsy value to hide it (can also be a react component)
onBlur | func | undefined | onBlur handler: `function(event) {}`
onBlurResetsInput | bool | true | whether to clear input on blur or not
onChange | func | undefined | onChange handler: `function(newValue) {}`
onClose | func | undefined | handler for when the menu closes: `function () {}`
onCloseResetsInput | bool | true | whether to clear input when closing the menu through the arrow
onFocus | func | undefined | onFocus handler: `function(event) {}`
onInputChange | func | undefined | onInputChange handler: `function(inputValue) {}`
onInputKeyDown | func | undefined | input keyDown handler; call `event.preventDefault()` to override default `Select` behavior: `function(event) {}`
onOpen | func | undefined | handler for when the menu opens: `function () {}`
onValueClick | func | undefined | onClick handler for value labels: `function (value, event) {}`
openOnFocus | bool | false | open the options menu when the input gets focus (requires searchable = true)
optionRenderer | func | undefined | function which returns a custom way to render the options in the menu
options | array | undefined | array of options
placeholder | string\|node | 'Select ...' | field placeholder, displayed when there's no value
scrollMenuIntoView | bool | true | whether the viewport will shift to display the entire menu when engaged
searchable | bool | true | whether to enable searching feature or not
searchPromptText | string\|node | 'Type to search' | label to prompt for search input
loadingPlaceholder | string\|node | 'Loading...' | label to prompt for loading search result
tabSelectsValue | bool | true | whether to select the currently focused value when the `[tab]` key is pressed
value | any | undefined | initial field value
valueKey | string | 'value' | the option property to use for the value
valueRenderer | func | undefined | function which returns a custom way to render the value selected `function (option) {}`
| Property | Type | Default | Description |
|:---|:---|:---|:---|
| addLabelText | string | 'Add "{label}"?' | text to display when `allowCreate` is true |
arrowRenderer | func | undefined | Renders a custom drop-down arrow to be shown in the right-hand side of the select: `arrowRenderer({ onMouseDown, isOpen })` |
| autoBlur | bool | false | Blurs the input element after a selection has been made. Handy for lowering the keyboard on mobile devices |
| autofocus | bool | undefined | autofocus the component on mount |
| autoload | bool | true | whether to auto-load the default async options set |
| autosize | bool | true | If enabled, the input will expand as the length of its value increases |
| backspaceRemoves | bool | true | whether pressing backspace removes the last item when there is no input value |
| backspaceToRemoveMessage | string | 'Press backspace to remove {last label}' | prompt shown in input when at least one option in a multiselect is shown, set to '' to clear |
| cache | bool | true | enables the options cache for `asyncOptions` (default: `true`) |
| className | string | undefined | className for the outer element |
| clearable | bool | true | should it be possible to reset value |
| clearAllText | string | 'Clear all' | title for the "clear" control when `multi` is true |
| clearRenderer | func | undefined | Renders a custom clear to be shown in the right-hand side of the select when clearable true: `clearRenderer()` |
| clearValueText | string | 'Clear value' | title for the "clear" control |
| resetValue | any | null | value to use when you clear the control |
| deleteRemoves | bool | true | whether pressing delete key removes the last item when there is no input value |
| delimiter | string | ',' | delimiter to use to join multiple values |
| disabled | bool | false | whether the Select is disabled or not |
| filterOption | func | undefined | method to filter a single option: `function(option, filterString)` |
| filterOptions | func | undefined | method to filter the options array: `function([options], filterString, [values])` |
| ignoreAccents | bool | true | whether to strip accents when filtering |
| ignoreCase | bool | true | whether to perform case-insensitive filtering |
| inputProps | object | {} | custom attributes for the Input (in the Select-control) e.g: `{'data-foo': 'bar'}` |
| isLoading | bool | false | whether the Select is loading externally or not (such as options being loaded) |
| joinValues | bool | false | join multiple values into a single hidden input using the `delimiter` |
| labelKey | string | 'label' | the option property to use for the label |
| loadOptions | func | undefined | function that returns a promise or calls a callback with the options: `function(input, [callback])` |
| matchPos | string | 'any' | (any, start) match the start or entire string when filtering |
| matchProp | string | 'any' | (any, label, value) which option property to filter on |
| menuBuffer | number | 0 | buffer of px between the base of the dropdown and the viewport to shift if menu doesnt fit in viewport |
| menuRenderer | func | undefined | Renders a custom menu with options; accepts the following named parameters: `menuRenderer({ focusedOption, focusOption, options, selectValue, valueArray })` |
| multi | bool | undefined | multi-value input |
| name | string | undefined | field name, for hidden `<input />` tag |
| noResultsText | string | 'No results found' | placeholder displayed when there are no matching search results or a falsy value to hide it (can also be a react component) |
| onBlur | func | undefined | onBlur handler: `function(event) {}` |
| onBlurResetsInput | bool | true | whether to clear input on blur or not |
| onChange | func | undefined | onChange handler: `function(newValue) {}` |
| onClose | func | undefined | handler for when the menu closes: `function () {}` |
| onCloseResetsInput | bool | true | whether to clear input when closing the menu through the arrow |
| onFocus | func | undefined | onFocus handler: `function(event) {}` |
| onInputChange | func | undefined | onInputChange handler: `function(inputValue) {}` |
| onInputKeyDown | func | undefined | input keyDown handler; call `event.preventDefault()` to override default `Select` behavior: `function(event) {}` |
| onOpen | func | undefined | handler for when the menu opens: `function () {}` |
| onValueClick | func | undefined | onClick handler for value labels: `function (value, event) {}` |
| openOnFocus | bool | false | open the options menu when the input gets focus (requires searchable = true) |
| optionRenderer | func | undefined | function which returns a custom way to render the options in the menu |
| options | array | undefined | array of options |
| placeholder | string\|node | 'Select ...' | field placeholder, displayed when there's no value |
| scrollMenuIntoView | bool | true | whether the viewport will shift to display the entire menu when engaged |
| searchable | bool | true | whether to enable searching feature or not |
| searchPromptText | string\|node | 'Type to search' | label to prompt for search input |
| loadingPlaceholder | string\|node | 'Loading...' | label to prompt for loading search result |
| tabSelectsValue | bool | true | whether to select the currently focused value when the `[tab]` key is pressed |
| value | any | undefined | initial field value |
| valueKey | string | 'value' | the option property to use for the value |
| valueRenderer | func | undefined | function which returns a custom way to render the value selected `function (option) {}` |

### Methods

Expand Down
1 change: 1 addition & 0 deletions src/Async.js
Expand Up @@ -13,6 +13,7 @@ const propTypes = {
React.PropTypes.node
]),
loadOptions: React.PropTypes.func.isRequired, // callback to load options asynchronously; (inputValue: string, callback: Function): ?Promise
multi: React.PropTypes.bool, // multi-value input
options: PropTypes.array.isRequired, // array of options
placeholder: React.PropTypes.oneOfType([ // field placeholder, displayed when there's no value (shared with Select)
React.PropTypes.string,
Expand Down
9 changes: 8 additions & 1 deletion src/Select.js
Expand Up @@ -1024,7 +1024,14 @@ const Select = React.createClass({

let focusedOption = this.state.focusedOption || selectedOption;
if (focusedOption && !focusedOption.disabled) {
const focusedOptionIndex = options.indexOf(focusedOption);
let focusedOptionIndex = -1;
options.some((option, index) => {
const isOptionEqual = option.value === focusedOption.value;
if (isOptionEqual) {
focusedOptionIndex = index;
}
return isOptionEqual;
});
if (focusedOptionIndex !== -1) {
return focusedOptionIndex;
}
Expand Down

0 comments on commit c3e9f46

Please sign in to comment.