Skip to content

Instantly share code, notes, and snippets.

@mattraykowski
Created April 10, 2018 14:48
Show Gist options
  • Save mattraykowski/082a03a538a66c017210c793264e633f to your computer and use it in GitHub Desktop.
Save mattraykowski/082a03a538a66c017210c793264e633f to your computer and use it in GitHub Desktop.
Dropdown Suggestions
// 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);
// 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