UNPKG

react-bootstrap-typeahead

Version:
112 lines (111 loc) 5.23 kB
import cx from 'classnames'; import PropTypes from 'prop-types'; import React, { forwardRef } from 'react'; import Typeahead from '../../core/Typeahead'; import ClearButton from '../ClearButton'; import Loader from '../Loader'; import Overlay from '../Overlay'; import RootClose from '../RootClose'; import Token from '../Token/Token'; import TypeaheadInputMulti from '../TypeaheadInputMulti'; import TypeaheadInputSingle from '../TypeaheadInputSingle'; import TypeaheadMenu from '../TypeaheadMenu'; import { getOptionLabel, isFunction, isSizeLarge, pick, preventInputBlur, } from '../../utils'; import { checkPropType, inputPropsType, sizeType } from '../../propTypes'; const propTypes = { clearButton: PropTypes.bool, inputProps: checkPropType(PropTypes.object, inputPropsType), isInvalid: PropTypes.bool, isLoading: PropTypes.bool, isValid: PropTypes.bool, renderInput: PropTypes.func, renderMenu: PropTypes.func, renderToken: PropTypes.func, size: sizeType, }; const defaultProps = { isLoading: false, }; const defaultRenderMenu = (results, menuProps, props) => (React.createElement(TypeaheadMenu, { ...menuProps, labelKey: props.labelKey, options: results, text: props.text })); const defaultRenderToken = (option, props, idx) => (React.createElement(Token, { disabled: props.disabled, key: idx, onRemove: props.onRemove, option: option, tabIndex: props.tabIndex }, getOptionLabel(option, props.labelKey))); const overlayPropKeys = [ 'align', 'dropup', 'flip', 'positionFixed', ]; function getOverlayProps(props) { return pick(props, overlayPropKeys); } class TypeaheadComponent extends React.Component { static propTypes = propTypes; static defaultProps = defaultProps; _referenceElement = null; render() { const { children, className, instanceRef, open, options, style } = this.props; return (React.createElement(Typeahead, { ...this.props, options: options, ref: instanceRef }, (props) => { const { hideMenu, isMenuShown, results } = props; const auxContent = this._renderAux(props); return (React.createElement(RootClose, { disabled: open || !isMenuShown, onRootClose: hideMenu }, (ref) => (React.createElement("div", { className: cx('rbt', { 'has-aux': !!auxContent, 'is-invalid': this.props.isInvalid, 'is-valid': this.props.isValid, }, className), ref: ref, style: { ...style, outline: 'none', position: 'relative', }, tabIndex: -1 }, this._renderInput({ ...props.getInputProps(this.props.inputProps), referenceElementRef: this.referenceElementRef, }, props), React.createElement(Overlay, { ...getOverlayProps(this.props), isMenuShown: isMenuShown, referenceElement: this._referenceElement }, (menuProps) => this._renderMenu(results, menuProps, props)), auxContent, isFunction(children) ? children(props) : children)))); })); } referenceElementRef = (referenceElement) => { this._referenceElement = referenceElement; }; _renderInput = (inputProps, props) => { const { isInvalid, isValid, multiple, renderInput, renderToken, size } = this.props; if (isFunction(renderInput)) { return renderInput(inputProps, props); } const commonProps = { ...inputProps, isInvalid, isValid, size, }; if (!multiple) { return React.createElement(TypeaheadInputSingle, { ...commonProps }); } const { labelKey, onRemove, selected } = props; return (React.createElement(TypeaheadInputMulti, { ...commonProps, placeholder: selected.length ? '' : inputProps.placeholder, selected: selected }, selected.map((option, idx) => (renderToken || defaultRenderToken)(option, { ...commonProps, labelKey, onRemove }, idx)))); }; _renderMenu = (results, menuProps, props) => { const { emptyLabel, id, maxHeight, newSelectionPrefix, paginationText, renderMenu, renderMenuItemChildren, } = this.props; return (renderMenu || defaultRenderMenu)(results, { ...menuProps, emptyLabel, id, maxHeight, newSelectionPrefix, paginationText, renderMenuItemChildren, }, props); }; _renderAux = ({ onClear, selected }) => { const { clearButton, disabled, isLoading, size } = this.props; let content; if (isLoading) { content = React.createElement(Loader, null); } else if (clearButton && !disabled && selected.length) { content = (React.createElement(ClearButton, { onClick: onClear, onMouseDown: preventInputBlur, size: size })); } return content ? (React.createElement("div", { className: cx('rbt-aux', { 'rbt-aux-lg': isSizeLarge(size) }) }, content)) : null; }; } export default forwardRef((props, ref) => (React.createElement(TypeaheadComponent, { ...props, instanceRef: ref })));