@navinc/base-react-components
Version:
Nav's Pattern Library
243 lines (239 loc) • 11.5 kB
JavaScript
;
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