diff --git a/__tests__/__snapshots__/index.spec.js.snap b/__tests__/__snapshots__/index.spec.js.snap
index c252d780..17932a7f 100644
--- a/__tests__/__snapshots__/index.spec.js.snap
+++ b/__tests__/__snapshots__/index.spec.js.snap
@@ -453,6 +453,149 @@ exports[` component renders with clearable 1`] = `
`;
+exports[` component renders with custom search function 1`] = `
+.emotion-6 {
+ box-sizing: border-box;
+ position: relative;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ border: 1px solid #ccc;
+ width: 100%;
+ border-radius: 2px;
+ padding: 2px 5px;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row;
+ direction: ltr;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ cursor: pointer;
+ min-height: 36px;
+ pointer-events: all;
+}
+
+.emotion-6:hover,
+.emotion-6:focus-within {
+ border-color: #0074D9;
+}
+
+.emotion-6:focus,
+.emotion-6:focus-within {
+ outline: 0;
+ box-shadow: 0 0 0 3px rgba(0,116,217,0.2);
+}
+
+.emotion-6 * {
+ box-sizing: border-box;
+}
+
+.emotion-2 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-flex-wrap: wrap;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+}
+
+.emotion-0 {
+ line-height: inherit;
+ border: none;
+ margin-left: 5px;
+ background: transparent;
+ font-size: smaller;
+}
+
+.emotion-0:focus {
+ outline: none;
+}
+
+.emotion-4 {
+ text-align: center;
+ pointer-events: none;
+ margin: 0 0 0 5px;
+ -webkit-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ transform: rotate(180deg);
+ cursor: pointer;
+}
+
+.emotion-4 svg {
+ width: 16px;
+ height: 16px;
+}
+
+.emotion-4:hover path {
+ stroke: #0074D9;
+}
+
+.emotion-4:focus {
+ outline: none;
+}
+
+.emotion-4:focus path {
+ stroke: #0074D9;
+}
+
+
+`;
+
exports[` component renders with loading 1`] = `
.emotion-8 {
box-sizing: border-box;
diff --git a/__tests__/components/Dropdown.spec.js b/__tests__/components/Dropdown.spec.js
index 5e43dace..19ad3452 100644
--- a/__tests__/components/Dropdown.spec.js
+++ b/__tests__/components/Dropdown.spec.js
@@ -10,7 +10,8 @@ const props = {
dropdownHeight: '300px'
},
state: {
- selectBounds: {}
+ selectBounds: {},
+ searchResults: [],
},
methods: {
searchResults: () => [],
diff --git a/__tests__/index.spec.js b/__tests__/index.spec.js
index 235cefb7..b64c2a21 100644
--- a/__tests__/index.spec.js
+++ b/__tests__/index.spec.js
@@ -1,5 +1,6 @@
import React from 'react';
import TestRenderer from 'react-test-renderer';
+import { LIB_NAME } from '../src/constants';
import Select from '../src/index';
@@ -59,9 +60,31 @@ describe(' component', () => {
expect(tree).toMatchSnapshot();
});
+ it(' renders with custom search function', () => {
+ const options = [
+ { id: 0, name: 'Zero' },
+ { id: 1, name: 'One' },
+ { id: 2, name: 'Two' },
+ ];
+
+ const searchFn = ({ props, state }) => {
+ return props.options.filter(({ name }) => new RegExp(state.search).test(name) );
+ };
+
+ const component = selectWithProps();
+
+ const input = component.root.find(element => element.props.className === `${LIB_NAME}-input`);
+
+ TestRenderer.act(() => input.props.onChange({ target: { value: 'Zer' } }));
+
+ expect(component.toTree().instance.state.search).toBe('Zer');
+ expect(component.toTree().instance.state.searchResults).toStrictEqual([{ id: 0, name: 'Zero'}])
+ expect(component.toJSON()).toMatchSnapshot();
+ });
+
it(' is disabled', () => {
const tree = selectWithProps().toJSON();
expect(tree).toMatchSnapshot();
- })
+ });
});
diff --git a/docs/src/examples/WithSearchFn.js b/docs/src/examples/WithSearchFn.js
new file mode 100644
index 00000000..72421e92
--- /dev/null
+++ b/docs/src/examples/WithSearchFn.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import { Heading } from './components/Heading';
+import Select from '../../../src';
+
+import {
+ getByPath,
+} from '../../../src/util';
+
+const WithSearchFn = ({ options, title }) => {
+ const onSearch = ({ props, state, methods }) => {
+ console.log({ props, state, methods });
+
+ const regexp = new RegExp(methods.safeString(state.search), 'i');
+ return methods
+ .sortBy()
+ .filter((item) =>
+ regexp.test(getByPath(item, props.searchBy) || getByPath(item, props.valueField))
+ );
+ };
+
+ return (
+
+
+
+
+ );
+};
+
+WithSearchFn.propTypes = {};
+
+export default WithSearchFn;
diff --git a/docs/src/pages/examples.js b/docs/src/pages/examples.js
index 9dcb34d2..48d2399b 100644
--- a/docs/src/pages/examples.js
+++ b/docs/src/pages/examples.js
@@ -28,6 +28,7 @@ import ExternalClear from '../examples/ExternalClear';
import AccessDataByPath from '../examples/AccessDataByPath';
import CustomDropdownHandle from '../examples/CustomDropdownHandle';
import WithAnimation from '../examples/WithAnimation';
+import WithSearchFn from '../examples/WithSearchFn';
const demoOptions = options.map((option) => ({
...option,
@@ -116,6 +117,10 @@ const Examples = () => (
+
+
+
+
diff --git a/docs/src/pages/state.md b/docs/src/pages/state.md
index 680ae084..b03f0c84 100644
--- a/docs/src/pages/state.md
+++ b/docs/src/pages/state.md
@@ -11,4 +11,6 @@ Access to current state of <Select/> component
| dropdown | boolean | check if dropdown is open |
| values | array | selected value(s) |
| search | string | current search string |
+| searchResults| string | Filtered search results
+|
| selectBounds | object | current `getBoundingClientRect()` of <Select/> |
diff --git a/package-lock.json b/package-lock.json
index aef639f1..88aefe33 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4139,7 +4139,8 @@
},
"minimist": {
"version": "1.2.0",
- "resolved": "",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"schema-utils": {
@@ -12782,7 +12783,8 @@
},
"minimist": {
"version": "1.2.0",
- "resolved": "",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"tapable": {
@@ -12851,7 +12853,8 @@
},
"minimist": {
"version": "1.2.0",
- "resolved": "",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"string-width": {
diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js
index 10a23829..407d0618 100644
--- a/src/components/Dropdown.js
+++ b/src/components/Dropdown.js
@@ -49,7 +49,7 @@ const Dropdown = ({ props, state, methods }) => (
{props.createNewLabel.replace('{search}', `"${state.search}"`)}
)}
- {methods.searchResults().length === 0 ? (
+ {state.searchResults.length === 0 ? (
(
methods={methods}
/>
) : (
- methods
- .searchResults()
- .map((item, itemIndex) => (
-
- ))
- )}
+ state.searchResults
+ .map((item, itemIndex) => (
+
+ ))
+ )}
)}
diff --git a/src/index.js b/src/index.js
index 5c1d88ba..1b5dbba8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -74,7 +74,8 @@ export class Select extends Component {
values: props.values,
search: '',
selectBounds: {},
- cursor: null
+ cursor: null,
+ searchResults: props.options,
};
this.methods = {
@@ -289,7 +290,9 @@ export class Select extends Component {
});
this.setState({
- search: event.target.value
+ search: event.target.value,
+ }, () => {
+ this.setState({ searchResults: this.searchResults() })
});
};
@@ -391,7 +394,7 @@ export class Select extends Component {
};
handleKeyDownFn = ({ event, state, props, methods, setState }) => {
- const { cursor } = state;
+ const { cursor, searchResults } = state;
const escape = event.key === 'Escape';
const enter = event.key === 'Enter';
const arrowUp = event.key === 'ArrowUp';
@@ -423,7 +426,7 @@ export class Select extends Component {
}
if (enter) {
- const currentItem = methods.searchResults()[cursor];
+ const currentItem = searchResults[cursor];
if (currentItem && !currentItem.disabled) {
if (props.create && valueExistInSelected(state.search, state.values, props)) {
return null;
@@ -433,7 +436,7 @@ export class Select extends Component {
}
}
- if ((arrowDown || (tab && state.dropdown)) && methods.searchResults().length === cursor) {
+ if ((arrowDown || (tab && state.dropdown)) && searchResults.length === cursor) {
return setState({
cursor: 0
});
@@ -453,7 +456,7 @@ export class Select extends Component {
if ((arrowUp || (shiftTab && state.dropdown)) && cursor === 0) {
setState({
- cursor: methods.searchResults().length
+ cursor: searchResults.length
});
}