react-dual-listbox
Version:
A feature-rich dual listbox for React.
111 lines (98 loc) • 3 kB
JSX
import PropTypes from 'prop-types';
import React, { Children, useContext } from 'react';
import { LanguageContext } from '../contexts';
import capitalizeFirstLetter from '../util/capitalizeFirstLetter';
import Filter from './Filter';
const propTypes = {
canFilter: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
controlKey: PropTypes.string.isRequired,
disabled: PropTypes.bool.isRequired,
filterValue: PropTypes.string.isRequired,
inputRef: PropTypes.func.isRequired,
selections: PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
).isRequired,
showNoOptionsText: PropTypes.bool.isRequired,
onDoubleClick: PropTypes.func.isRequired,
onFilterChange: PropTypes.func.isRequired,
onKeyUp: PropTypes.func.isRequired,
onSelectionChange: PropTypes.func.isRequired,
actions: PropTypes.node,
id: PropTypes.string,
};
function ListBox({
canFilter,
children,
controlKey,
disabled,
filterValue,
inputRef,
selections,
showNoOptionsText,
onDoubleClick,
onFilterChange,
onKeyUp,
onSelectionChange,
actions = null,
id = null,
}) {
// Grab language-specific text
const {
[`${controlKey}Header`]: header,
[`no${capitalizeFirstLetter(controlKey)}Options`]: noOptionsText,
} = useContext(LanguageContext);
// Append the control key to the ID, if provided
const inputId = id ? `${id}-${controlKey}` : null;
function renderFilter() {
if (!canFilter) {
return null;
}
return (
<Filter
controlKey={controlKey}
disabled={disabled}
filterValue={filterValue}
onFilterChange={onFilterChange}
/>
);
}
function renderSelect() {
if (showNoOptionsText && Children.count(children) === 0) {
return (
<div className="rdl-no-options">
{noOptionsText}
</div>
);
}
return (
<div className="rdl-control-container">
{actions}
<select
className="rdl-control"
disabled={disabled}
id={`${inputId}`}
multiple
ref={inputRef}
value={selections}
onChange={onSelectionChange}
onDoubleClick={onDoubleClick}
onKeyUp={onKeyUp}
>
{children}
</select>
</div>
);
}
return (
<div className={`rdl-list-box rdl-${controlKey}`}>
<label className="rdl-control-label" htmlFor={inputId}>
{header}
</label>
{renderFilter()}
{renderSelect()}
</div>
);
}
ListBox.propTypes = propTypes;
export default ListBox;