Skip to content

Commit

Permalink
Add showDropdownAtStart prop
Browse files Browse the repository at this point in the history
Allow the searchbox to act as a `filter` dropdown with initial values.
Yields all results when the search value is blank.
  • Loading branch information
PatrickDesign committed Dec 16, 2020
1 parent 391aa68 commit 27ffae4
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ keys|all[Array]|List of properties that will be searched. This also supports nes
list|null|Array of properties to be filtered.
placeholder|'Search'|Placeholder of the searchbox
resultsTemplate| Func | Template of the dropdown divs
showDropdownAtStart|false|Allow the searchbox to act as a `filter` dropdown with initial values. Yields all results when the search value is blank.
shouldSort| true | Whether to sort the result list, by score.
sortFn|`Array.prototype.sort`|The function that is used for sorting the result list.
threshold|0.6|At what point does the match algorithm give up. A threshold of `0.0` requires a perfect match (of both letters and location), a threshold of `1.0` would match anything.
Expand Down
50 changes: 45 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function defaultResultsTemplate(props, state, styl, clickHandler) {
return state.results.map((val, i) => {
const style = state.selectedIndex === i ? {...styl.selectedResultStyle, ...props.selectedListItemStyle} : {...styl.resultsStyle, ...props.listItemStyle };
return (
<div key={i} style={style} onClick={() => clickHandler(i)}>
<div tabIndex="0" key={i} style={style} onClick={() => clickHandler(i)}>
{val[props.keyForDisplayName]}
</div>
);
Expand All @@ -79,6 +79,7 @@ export default class FuzzySearch extends Component {
location: PropTypes.number,
placeholder: PropTypes.string,
resultsTemplate: PropTypes.func,
showDropdownAtStart: PropTypes.bool,
shouldSort: PropTypes.bool,
sortFn: PropTypes.func,
threshold: PropTypes.number,
Expand All @@ -103,6 +104,7 @@ export default class FuzzySearch extends Component {
width: 430,
placeholder: 'Search',
resultsTemplate: defaultResultsTemplate,
showDropdownAtStart: false,
shouldSort: true,
sortFn(a, b) {
return a.score - b.score;
Expand All @@ -122,6 +124,7 @@ export default class FuzzySearch extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: !this.props.showDropdownAtStart,
results: [],
selectedIndex: 0,
selectedValue: {},
Expand All @@ -131,6 +134,9 @@ export default class FuzzySearch extends Component {
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleMouseClick = this.handleMouseClick.bind(this);
this.fuse = new Fuse(props.list, this.getOptions());
this.setDropdownRef = ref => {
this.dropdownRef = ref;
};
}

getOptions() {
Expand Down Expand Up @@ -168,8 +174,12 @@ export default class FuzzySearch extends Component {
}

handleChange(e) {
const shouldDisplayAllListItems = this.props.showDropdownAtStart && !e.target.value;

this.setState({
results: this.fuse.search(e.target.value).slice(0, this.props.maxResults - 1),
results: shouldDisplayAllListItems
? this.props.list
: this.fuse.search(e.target.value).slice(0, this.props.maxResults - 1),
value: e.target.value,
});
}
Expand Down Expand Up @@ -219,7 +229,15 @@ export default class FuzzySearch extends Component {
}

render() {
const { autoFocus, className, list, placeholder, resultsTemplate, width } = this.props;
const {
autoFocus,
className,
list,
placeholder,
resultsTemplate,
showDropdownAtStart,
width,
} = this.props;

// Update the search space list
if (this.fuse.setCollection && list) {
Expand All @@ -229,7 +247,21 @@ export default class FuzzySearch extends Component {
const mainClass = classNames('react-fuzzy-search', className);

return (
<div className={mainClass} style={{ width }} onKeyDown={this.handleKeyDown}>
<div
className={mainClass}
ref={this.setDropdownRef}
style={{ width }}
onBlur={(e) => {
if (this.dropdownRef.contains(e.relatedTarget)) return;

if (showDropdownAtStart) {
this.setState({
isOpen: false,
});
}
}}
onKeyDown={this.handleKeyDown}
>
<div style={{...styles.searchBoxWrapper, ...this.props.inputWrapperStyle}}>
<input
autoFocus={autoFocus}
Expand All @@ -238,9 +270,17 @@ export default class FuzzySearch extends Component {
style={{...styles.searchBoxStyle, ...this.props.inputStyle}}
type="text"
value={this.state.value}
onFocus={() => {
if (showDropdownAtStart) {
this.setState({
isOpen: true,
results: this.state.value ? this.state.results : list,
});
}
}}
/>
</div>
{this.state.results && this.state.results.length > 0 && (
{this.state.isOpen && this.state.results && this.state.results.length > 0 && (
<div style={{...styles.resultsWrapperStyle, ...this.props.listWrapperStyle}}>
{resultsTemplate(this.props, this.state, styles, this.handleMouseClick)}
</div>
Expand Down
9 changes: 9 additions & 0 deletions src/stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ storiesOf('SearchBox', module)
/>
);
})
.add('Show Dropdown at Start', () => (
<FuzzySearch
showDropdownAtStart
list={list}
keys={['author', 'title']}
width={430}
onSelect={action('selected')}
/>
))
.add('Passthrough Options', () => {
const template = (props, state, styles, click) =>
state.results.map(({ item, matches }, i) => {
Expand Down
20 changes: 20 additions & 0 deletions src/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,24 @@ describe('<FuzzySearch />', () => {

expect(wrapper.find('input')).to.exist;
})

it('should display all options onFocus when showDropdownAtStart passed in', () => {
const onChange = sinon.spy();
const wrapper = mount(
<FuzzySearch
keyForDisplayName="author"
list={list}
onSelect={onChange}
keys={['author', 'title']}
options={{ includeMatches: true }}
showDropdownAtStart
/>,
);

const input = wrapper.find('input');

input.simulate('focus');

expect(wrapper.state('results').length).to.not.equal(0);
});
});

0 comments on commit 27ffae4

Please sign in to comment.