UNPKG

@navinc/base-react-components

Version:
243 lines (239 loc) 11.5 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SearchInput = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const styled_components_1 = __importDefault(require("styled-components")); const loading_dots_js_1 = require("./loading-dots.js"); const icon_js_1 = require("./icon.js"); const shared_js_1 = require("./form-elements/shared.js"); const copy_js_1 = require("./copy.js"); const utils_1 = require("@navinc/utils"); const use_debounce_1 = require("use-debounce"); const id = (id) => id; const SearchInputContainer = styled_components_1.default.div.withConfig({ displayName: "brc-sc-SearchInputContainer", componentId: "brc-sc-1ogiirv" }) ` width: 100%; `; const ResultsContainer = styled_components_1.default.div.withConfig({ displayName: "brc-sc-ResultsContainer", componentId: "brc-sc-1mckfdl" }) ` position: relative; z-index: 2; & > ${shared_js_1.Helper} { margin-left: ${({ theme }) => theme.gu(2)}; } `; const ResultContainer = styled_components_1.default.div.withConfig({ displayName: "brc-sc-ResultContainer", componentId: "brc-sc-ztsn0h" }) ` cursor: pointer; outline: none; padding: 16px; border-bottom: 1px solid ${({ theme }) => theme.navNeutral300}; ${({ isActive, theme }) => isActive && `background-color: ${theme.navNeutral100}; border: 4px solid ${theme.navStatusPositive500};`} &:hover { background-color: ${({ theme }) => theme.navNeutral100}; } &:focus { outline: ${({ theme }) => theme.focusOutline}; } `; const Results = styled_components_1.default.div.withConfig({ displayName: "brc-sc-Results", componentId: "brc-sc-1625sii" }) ` background-color: ${({ theme }) => theme.navNeutralLight}; border: solid 1px ${({ theme }) => theme.navNeutral300}; border-top: none; border-radius: 0 0 8px 8px; position: ${({ shouldPositionResultsRelative }) => (shouldPositionResultsRelative ? 'relative' : 'absolute')}; top: 0; overflow-y: auto; max-height: ${({ resultsMaxHeight }) => resultsMaxHeight || '300px'}; width: 100%; /* prettier-ignore */ ${ResultContainer}:last-child { border-bottom: none; } `; const StyledFieldWrapper = (0, styled_components_1.default)(shared_js_1.FieldWrapper).withConfig({ displayName: "brc-sc-StyledFieldWrapper", componentId: "brc-sc-t4nnx1" }) ` & ${icon_js_1.Icon}, & ${loading_dots_js_1.LoadingDots} { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); } & ${icon_js_1.Icon} { width: 24px; } & ${loading_dots_js_1.LoadingDots} { color: ${({ theme }) => theme.navPrimary}; width: 56px; } & ${shared_js_1.Input} { text-overflow: ellipsis; padding-right: 40px; ${({ shouldShowDropDown }) => shouldShowDropDown && 'border-radius: 4px 4px 0 0;'} } `; const StyledNoResults = styled_components_1.default.div.withConfig({ displayName: "brc-sc-StyledNoResults", componentId: "brc-sc-1amzcra" }) ` align-items: center; display: flex; flex-direction: column; margin-bottom: 24px; margin-top: 24px; `; const NoResultsIcon = (0, styled_components_1.default)(icon_js_1.Icon).withConfig({ displayName: "brc-sc-NoResultsIcon", componentId: "brc-sc-px8svc" }) ` color: ${({ theme }) => theme.navNeutral400}; margin-bottom: 8px; `; const DefaultNoResults = ({ query }) => ((0, jsx_runtime_1.jsxs)(StyledNoResults, { children: [(0, jsx_runtime_1.jsx)(NoResultsIcon, { name: "actions/circle-faq" }), (0, jsx_runtime_1.jsxs)(copy_js_1.Copy, { children: ["No results for \"", query, "\""] })] })); const _SearchInput = (_a) => { var { autoFocus, className, errors = [], helperText, isLoading, isInvalid, label, lede, name, NoResults, onBlur = utils_1.noop, onChange = utils_1.noop, onFocus = utils_1.noop, Result, required, results = [], resultsMaxHeight, resultToQuery = id, search, shouldPositionResultsRelative, touched, type, value } = _a, inputProps = __rest(_a, ["autoFocus", "className", "errors", "helperText", "isLoading", "isInvalid", "label", "lede", "name", "NoResults", "onBlur", "onChange", "onFocus", "Result", "required", "results", "resultsMaxHeight", "resultToQuery", "search", "shouldPositionResultsRelative", "touched", "type", "value"]); const [focusedResultIndex, setFocusedResultIndex] = (0, react_1.useState)(-1); const [canBeOpen, setCanBeOpen] = (0, react_1.useState)(false); const [query, setQuery] = (0, react_1.useState)(''); const [lastSearchedQuery, setLastSearchedQuery] = (0, react_1.useState)(''); const inputRef = (0, react_1.useRef)(null); const resultsRef = (0, react_1.useRef)(null); const shouldShowDropDown = !!(query.length && canBeOpen && query === lastSearchedQuery && !isLoading); const shouldShowResults = !!(shouldShowDropDown && results.length); const shouldShowNoResults = !!(shouldShowDropDown && !results.length); const RenderNoResults = NoResults || DefaultNoResults; const isVisited = touched || !!value; (0, react_1.useEffect)(() => { if (!value) { return; } const newQuery = resultToQuery(value); if (!newQuery) { return; } setQuery(newQuery); }, [resultToQuery, value]); (0, react_1.useEffect)(() => { if (autoFocus && inputRef.current) { (0, utils_1.focusWithoutScroll)(inputRef.current); } }, [autoFocus]); const searchDebounced = (0, use_debounce_1.useDebouncedCallback)((query) => { setLastSearchedQuery(query); search(query); setFocusedResultIndex(-1); }, 500); const handleChange = ({ target }) => { var _a; const newQuery = (_a = target.value) !== null && _a !== void 0 ? _a : ''; setQuery(newQuery); onChange({ target: { name, value: null, }, }); if (newQuery.length > 0) { searchDebounced(newQuery); setCanBeOpen(true); } }; const handleInputFocus = (event) => { setCanBeOpen(true); onFocus(event); }; const focusResult = (index) => { var _a, _b, _c; const ref = (_b = (_a = resultsRef.current) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b[index]; if (ref) { setFocusedResultIndex(index); ref.focus(); (_c = inputRef.current) === null || _c === void 0 ? void 0 : _c.focus(); } }; const goToNextResult = () => { const newIndex = focusedResultIndex + 1; if (newIndex < results.length) { focusResult(newIndex); } }; const goToPreviousResult = () => { const newIndex = focusedResultIndex - 1; if (newIndex > -2) { focusResult(newIndex); } }; const closeResults = () => { setCanBeOpen(false); setFocusedResultIndex(-1); }; const onSelectResult = (clickedResult) => { const result = clickedResult || results[focusedResultIndex]; closeResults(); onChange({ target: { name, value: result, }, }); }; const handleBlurOnInput = (event) => { if (!resultsRef.current || (resultsRef.current && !resultsRef.current.contains(event.relatedTarget))) { closeResults(); onBlur(event); } }; const handleKeyDownOnInput = (event) => { switch (event.keyCode) { case 40: // Down Arrow if (shouldShowResults) { event.preventDefault(); goToNextResult(); } else { setCanBeOpen(true); } break; case 9: // Tab if (shouldShowResults) { event.preventDefault(); if (event.shiftKey) { goToPreviousResult(); } else { goToNextResult(); } } break; case 38: // Up Arrow if (shouldShowResults) { event.preventDefault(); goToPreviousResult(); } break; case 27: // Escape if (focusedResultIndex > -1) { setFocusedResultIndex(-1); } else { setQuery(''); } break; case 13: // Enter if (focusedResultIndex > -1) { event.preventDefault(); onSelectResult(); } break; } }; return ((0, jsx_runtime_1.jsxs)(SearchInputContainer, { className: className, children: [(0, jsx_runtime_1.jsxs)(StyledFieldWrapper, { shouldShowDropDown: shouldShowDropDown, children: [lede && (0, jsx_runtime_1.jsx)(copy_js_1.Copy, { bold: true, children: lede }), (0, jsx_runtime_1.jsxs)(shared_js_1.Field, { isVisited: isVisited, children: [(0, jsx_runtime_1.jsx)(shared_js_1.Input, Object.assign({ autoComplete: "off", "data-testid": "search-input:input", name: name, onBlur: handleBlurOnInput, onChange: handleChange, onFocus: handleInputFocus, onKeyDown: handleKeyDownOnInput, type: type, ref: inputRef, required: required, value: query, isInvalid: isInvalid }, inputProps)), isLoading ? (0, jsx_runtime_1.jsx)(loading_dots_js_1.LoadingDots, {}) : (0, jsx_runtime_1.jsx)(icon_js_1.Icon, { name: "system/search" }), (0, jsx_runtime_1.jsx)(shared_js_1.Label, { required: required, children: (0, utils_1.capitalize)(label) })] })] }), (0, jsx_runtime_1.jsxs)(ResultsContainer, { children: [shouldShowDropDown && ((0, jsx_runtime_1.jsxs)(Results, { resultsMaxHeight: resultsMaxHeight, ref: resultsRef, shouldPositionResultsRelative: shouldPositionResultsRelative, children: [shouldShowNoResults && (0, jsx_runtime_1.jsx)(RenderNoResults, { query: query }), shouldShowResults && results.map((result, index) => ((0, jsx_runtime_1.jsx)(ResultContainer, { isActive: focusedResultIndex === index, onMouseDown: () => onSelectResult(result), tabIndex: 0, children: (0, jsx_runtime_1.jsx)(Result, { result: result }) }, JSON.stringify(result))))] })), helperText && (0, jsx_runtime_1.jsx)(shared_js_1.Helper, { hasSpaceForHelper: true, helperText: helperText }), (0, jsx_runtime_1.jsx)(shared_js_1.Errors, { hasSpaceForErrors: true, children: !!errors.length && errors.map((err, i) => (0, jsx_runtime_1.jsx)(shared_js_1.Err, { children: err }, `err-${i}`)) })] })] })); }; exports.SearchInput = (0, styled_components_1.default)(_SearchInput) ``; //# sourceMappingURL=search-input.js.map