UNPKG

google-typeahead

Version:
247 lines (228 loc) 8.4 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import React, { useEffect, useState } from "react"; import PropTypes from 'prop-types'; import ClickAwayListener from "./ListenClickAway/ClickAwayListener"; import "./index.css"; import styled from "styled-components"; const Base = styled.div`color: rgba(0, 0, 0, 0.87);transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;background-color: #fff;box-shadow: 0 1px 6px 0 rgba(32, 33, 36, 0.28);position: relative;${props => { if (props.open) { return `&:after { width: 100%; height: 15px; display: block; background-color: white; content: " "; position: absolute; bottom: -2px; z-index: ${props.zIndex ? typeof props.zIndex === "string" ? parseInt(props.zIndex) + 1 : props.zIndex + 1 : 2};}border-top-left-radius:22px; border-top-right-radius:22px;`; } else { return `border-radius:22px`; } }}`; export default function GoogleTypeahead(props) { const { zIndex, id, canCreate, limit, className, options, value: search, setValue, isCaseSensitive, defaultOpen, emptyLabel, LeftSideComponent, RightSideComponent, onClick, onChange, onKeyDown, ...remainingProps } = props; if (options.length > 0 && typeof options[0] === "object" && typeof id !== "string") { throw new Error("If options are an object, you must specify a string key to filter by as a prop named 'id'"); } const filterOptions = value => { if (options.length > 0 && typeof options[0] === "object") { if (isCaseSensitive) { return limit ? options.filter(opt => opt[id].indexOf(value) !== -1).slice(0, limit) : options.filter(opt => opt[id].indexOf(value) !== -1); } else { return limit ? options.filter(opt => opt[id].toLowerCase().indexOf(value.toLowerCase()) !== -1).slice(0, limit) : options.filter(opt => opt[id].toLowerCase().indexOf(value.toLowerCase()) !== -1); } } else { if (isCaseSensitive) { return limit ? options.filter(opt => opt.indexOf(value) !== -1).slice(0, limit) : options.filter(opt => opt.indexOf(value) !== -1); } else { return limit ? options.filter(opt => opt.toLowerCase().indexOf(value.toLowerCase()) !== -1).slice(0, limit) : options.filter(opt => opt.toLowerCase().indexOf(value.toLowerCase()) !== -1); } } }; const [open, setOpen] = useState(Boolean(defaultOpen)); const [offset, setOffset] = useState(0); const [remainingOptions, setRemainingOptions] = useState(filterOptions(search)); useEffect(() => { if (search.length > 0) { refreshSuggestions(); } }, []); const refreshSuggestions = value => { setRemainingOptions(filterOptions(value)); }; const handleEnter = e => { if (remainingOptions.length > 0) { setOpen(false); e.target.blur(); setValue(remainingOptions[offset]); refreshSuggestions(remainingOptions[offset]); setOffset(0); } else if (canCreate) { setOpen(false); e.target.blur(); } }; const handleClickAway = () => { setOpen(false); setOffset(0); }; const handleClick = option => { setValue(option); refreshSuggestions(option); setOpen(false); setOffset(0); }; const handleKeyDown = e => { if (e.keyCode === 13) { handleEnter(e); setOffset(0); } else if (e.keyCode === 38) { e.preventDefault(); if (offset > 0) { setOffset(offset - 1); setValue(remainingOptions[offset - 1]); } } else if (e.keyCode === 40) { if (offset < remainingOptions.length - 1) { setOffset(offset + 1); setValue(remainingOptions[offset + 1]); } } if (onKeyDown) { onKeyDown(e); } }; const handleOnClick = e => { setOpen(true); if (onClick) { onClick(e); } }; const handleChange = e => { refreshSuggestions(e.target.value); setOffset(0); setValue(e.target.value); if (onChange) { onChange(e); } }; return /*#__PURE__*/React.createElement("div", { style: { display: "flex", justifyContent: "center", marginTop: "1rem" } }, /*#__PURE__*/React.createElement(ClickAwayListener, { onClickAway: () => handleClickAway() }, /*#__PURE__*/React.createElement(Base, { className: className ? className : undefined, open: open, zIndex: zIndex }, /*#__PURE__*/React.createElement("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", paddingLeft: "1rem", paddingRight: "1rem" } }, LeftSideComponent && /*#__PURE__*/React.createElement(LeftSideComponent, null), /*#__PURE__*/React.createElement("input", _extends({ onClick: () => handleOnClick(), className: "google-typeahead-input", onKeyDown: e => handleKeyDown(e), onChange: e => handleChange(e), value: search }, remainingProps)), RightSideComponent && /*#__PURE__*/React.createElement(RightSideComponent, null)), /*#__PURE__*/React.createElement("div", { className: "google-typeahead-dropdown", style: { zIndex: zIndex ? zIndex : "1", paddingTop: open ? "2px" : "0px" } }, open && (remainingOptions.length === 0 ? canCreate ? /*#__PURE__*/React.createElement("li", { className: "google-typeahead-item google-typeahead-selected", style: { borderBottomRightRadius: "22px", borderBottomLeftRadius: "22px" } }, /*#__PURE__*/React.createElement("div", { className: "google-typeahead-text" }, /*#__PURE__*/React.createElement("b", null, search))) : /*#__PURE__*/React.createElement("li", { className: "google-typeahead-item", style: { borderBottomRightRadius: "22px", borderBottomLeftRadius: "22px" } }, /*#__PURE__*/React.createElement("div", { className: "google-typeahead-text" }, emptyLabel ? emptyLabel : "No Items Found")) : remainingOptions.map((opt, index) => { return /*#__PURE__*/React.createElement("li", { className: index === offset ? "google-typeahead-item google-typeahead-selected" : "google-typeahead-item", key: index, onClick: () => handleClick(opt), style: remainingOptions.length - 1 === index ? { borderBottomRightRadius: "22px", borderBottomLeftRadius: "22px" } : undefined }, /*#__PURE__*/React.createElement("div", { className: "google-typeahead-text" }, /*#__PURE__*/React.createElement(BoldedText, { text: typeof remainingOptions[0] === "object" ? opt[id] : opt, shouldBeBold: search, isCaseSensitive: isCaseSensitive }), " ")); })))))); } function BoldedText({ text, shouldBeBold, isCaseSensitive }) { const textArray = isCaseSensitive ? text.split(shouldBeBold) : text.toLowerCase().split(shouldBeBold.toLowerCase()); var count = 0; return /*#__PURE__*/React.createElement("span", null, textArray.map((item, index) => { count += index === 0 ? item.length : item.length + shouldBeBold.length; return /*#__PURE__*/React.createElement(Wrapper, { key: index }, text.substring(count - item.length, count), index !== textArray.length - 1 && /*#__PURE__*/React.createElement("b", null, isCaseSensitive ? shouldBeBold : text.substring(count, count + shouldBeBold.length))); })); } const Wrapper = ({ children }) => /*#__PURE__*/React.createElement(React.Fragment, null, children); GoogleTypeahead.propTypes = { options: PropTypes.array.isRequired, setValue: PropTypes.func.isRequired, value: PropTypes.string.isRequired, canCreate: PropTypes.bool, isCaseSensitive: PropTypes.bool, defaultOpen: PropTypes.bool, className: PropTypes.string, onClick: PropTypes.func, onChange: PropTypes.func, onBlur: PropTypes.func, onKeyDown: PropTypes.func, limit: PropTypes.number, id: PropTypes.string, emptyLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), zIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), LeftSideComponent: PropTypes.elementType, RightSideComponent: PropTypes.elementType };