Created
April 10, 2018 14:48
-
-
Save mattraykowski/082a03a538a66c017210c793264e633f to your computer and use it in GitHub Desktop.
Dropdown Suggestions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// My gripe with this is that it's not enough different from <Autocomplete /> to warrant its existance. | |
// You're assuming that the item looks like this: | |
// ``` | |
// { | |
// value: 'a value', | |
// label: 'a label', | |
// unique: 'unique-key' | |
// } | |
// | |
// Literally nothing we send to this as 'items' will have this object structure. So we'll need to | |
// override the following props for every usage: shouldItemRender, renderItem, getItemValue. You may | |
// need to override others. The only thing you're getting is implied handling of the lookup field. | |
import React from 'react'; | |
import { compose, withState, withHandlers } from 'recompose'; | |
import classNames from 'classnames'; | |
import Autocomplete from 'react-autocomplete'; | |
export const defaultRenderItem = (item, isHighlighted) => ( | |
<div | |
key={`${item.value}-${item.unique}`} | |
className={classNames('item', { | |
'item-highlighted': isHighlighted, | |
})} | |
> | |
{item.label} | |
</div> | |
); | |
export const defaultGetItemValue = item => item.label; | |
export const defaultShouldItemRender = () => true; | |
export const DropDownComponent = ({ | |
items, | |
shouldItemRender, | |
renderItem, | |
handleChange, | |
handleSelect, | |
lookup, | |
}) => ( | |
<Autocomplete | |
shouldItemRender={ | |
shouldItemRender ? shouldItemRender : defaultShouldItemRender | |
} | |
renderItem={renderItem ? renderItem : defaultRenderItem} | |
value={lookup} | |
items={items} | |
getItemValue={getItemValue ? getItemValue : defaultGetItemValue} | |
onChange={handleChange} | |
onSelect={handleSelect} | |
/> | |
); | |
const handleChange = ({ setLookup, onChange }) => e => { | |
setLookup(e.target.value); | |
if (typeof onChange === 'function') { | |
onChange(e); | |
} | |
}; | |
const handleSelect = ({ setLookup, onSelect }) => item => { | |
setLookup(item.value); | |
if (typeof onSelect === 'function') { | |
onSelect(item); | |
} | |
}; | |
export const DropDown = compose( | |
withState('lookup', 'setLookup', ''), | |
withHandlers({ | |
handleChange, | |
handleSelect, | |
handleRenderItem, | |
}), | |
)(DropDownComponent); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// If you make the dropdown specific to users then you can provide a lot of | |
// reasonable default behavior with very little need to override the provided | |
// behavior. You'll, obviously, need to provide an array of users and an onSelect | |
// function in both scenarios. But here you only need to modify the other properties | |
// if you have a special use-case in your UI. For example you don't want to display | |
// the display name but instead the username. You want to change what it matches when | |
// typing ahead, etc. | |
import React from 'react'; | |
import { compose, withState, withHandlers } from 'recompose'; | |
import PropTypes from 'prop-types'; | |
import classNames from 'classnames'; | |
import Autocomplete from 'react-autocomplete'; | |
export const defaultRenderUser = (user, isHighlighted) => ( | |
<div | |
key={`${user.username}`} | |
className={classNames('item', { | |
'item-highlighted': isHighlighted, | |
})} | |
> | |
{item.displayName} | |
</div> | |
); | |
export const defaultGetUserValue = item => item.displayName; | |
export const defaultShouldUserRender = (user, value) => | |
user.displayName.toUpperCase().includes(value.toUpperCase()) || | |
user.username.toUpperCase().includes(value.toUpperCase()); | |
export const UsersDropdownComponent = ({ | |
users, | |
shouldUserRender, | |
renderUser, | |
getUserValue, | |
handleSelect, | |
handleChange, | |
lookup, | |
}) => ( | |
<Autocomplete | |
shouldItemRender={ | |
shouldUserRender ? shouldUserRender : defaultShouldUserRender | |
} | |
renderItem={renderUser ? renderUser : defaultRenderUser} | |
value={lookup} | |
items={users} | |
getItemValue={getUserValue ? getUserValue : defaultGetUserValue} | |
onChange={handleChange} | |
onSelect={handleSelect} | |
/> | |
); | |
const handleChange = ({ setLookup, onChange }) => e => { | |
setLookup(e.target.value); | |
if (typeof onChange === 'function') { | |
onChange(e); | |
} | |
}; | |
const handleSelect = ({ setLookup, onSelect }) => user => { | |
setLookup(user.displayName); | |
if (typeof onSelect === 'function') { | |
onSelect(user); | |
} | |
}; | |
export const UserDropdown = compose( | |
withState('lookup', 'setLookup', ''), | |
withHandlers({ | |
handleChange, | |
handleSelect, | |
handleRenderItem, | |
}), | |
)(DropDownComponent); | |
UserDropdown.propTypes = { | |
users: PropTypes.array.isRequired, | |
onSelect: PropTypes.func.isRequired, | |
onChange: PropTypes.func, | |
renderUser: PropTypes.func, | |
shouldUserRender: PropTypes.func, | |
getUserValue: PropTypes.func, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment