@navinc/base-react-components
Version:
Nav's Pattern Library
265 lines (262 loc) • 13.1 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 = __importDefault(require("./loading-dots.js"));
const icon_js_1 = __importDefault(require("./icon.js"));
const shared_js_1 = require("./form-elements/shared.js");
const copy_js_1 = __importDefault(require("./copy.js"));
const utils_1 = require("@navinc/utils");
const use_debounce_1 = require("use-debounce");
const prop_types_1 = __importDefault(require("prop-types"));
const is_rebrand_js_1 = __importDefault(require("./is-rebrand.js"));
const id = (id) => id;
const SearchInputContainer = styled_components_1.default.div.withConfig({ displayName: "brc-sc-SearchInputContainer", componentId: "brc-sc-1tkz17d" }) `
width: 100%;
`;
const ResultsContainer = styled_components_1.default.div.withConfig({ displayName: "brc-sc-ResultsContainer", componentId: "brc-sc-8e5pn8" }) `
position: relative;
z-index: 2;
& > ${shared_js_1.Helper} {
margin-left: ${({ theme }) => theme.gu(2)};
}
`;
const getResultContainerBackgroundColor = (isActive, theme) => {
if ((0, is_rebrand_js_1.default)(theme) && isActive)
return `background-color: ${theme.navNeutral100}; border: 4px solid ${theme.navStatusPositive500}`;
return isActive && `background-color: ${theme.neutral100};`;
};
const ResultContainer = styled_components_1.default.div.withConfig({ displayName: "brc-sc-ResultContainer", componentId: "brc-sc-ed8c26" }) `
cursor: pointer;
outline: none;
padding: 16px;
border-bottom: 1px solid ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral300 : theme.neutral300)};
${({ isActive, theme }) => getResultContainerBackgroundColor(isActive, theme)};
&:hover {
background-color: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral100 : theme.neutral100)};
}
&:focus {
outline: ${({ theme }) => theme.focusOutline};
}
`;
const Results = styled_components_1.default.div.withConfig({ displayName: "brc-sc-Results", componentId: "brc-sc-1avlx1y" }) `
background-color: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navSecondary100 : theme.white)};
border: solid 1px ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral300 : theme.neutral300)};
border-top: none;
border-radius: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? '0 0 8px 8px' : '0 0 4px 4px')};
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-13fj46g" }) `
& ${icon_js_1.default}, & ${loading_dots_js_1.default} {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
}
& ${icon_js_1.default} {
width: 24px;
}
& ${loading_dots_js_1.default} {
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-9i7w38" }) `
align-items: center;
display: flex;
flex-direction: column;
margin-bottom: 24px;
margin-top: 24px;
`;
const NoResultsIcon = (0, styled_components_1.default)(icon_js_1.default).withConfig({ displayName: "brc-sc-NoResultsIcon", componentId: "brc-sc-f379za" }) `
color: ${({ theme }) => ((0, is_rebrand_js_1.default)(theme) ? theme.navNeutral400 : theme.neutral400)};
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.default, { children: ["No results for \"", query, "\""] })] }));
const SearchInput = (_a) => {
var { autoFocus, className, errors, helperText, isLoading, isInvalid, label, lede, name, NoResults, onBlur, onChange, onFocus, Result, required, results, resultsMaxHeight, resultToQuery, 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)(() => {
resultToQuery(value) && setQuery(resultToQuery(value) || '');
}, [resultToQuery, value]);
(0, react_1.useEffect)(() => {
if (autoFocus) {
(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;
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();
inputRef.current.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, Object.assign({ className: className }, { children: [(0, jsx_runtime_1.jsxs)(StyledFieldWrapper, Object.assign({ shouldShowDropDown: shouldShowDropDown }, { children: [lede && (0, jsx_runtime_1.jsx)(copy_js_1.default, Object.assign({ bold: true }, { children: lede })), (0, jsx_runtime_1.jsxs)(shared_js_1.Field, Object.assign({ isInvalid: isInvalid, isVisited: isVisited, required: required, type: type }, { 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.default, {}) : (0, jsx_runtime_1.jsx)(icon_js_1.default, { name: "system/search" }), (0, jsx_runtime_1.jsx)(shared_js_1.Label, Object.assign({ required: required, value: query }, { children: (0, utils_1.capitalize)(label) }))] }))] })), (0, jsx_runtime_1.jsxs)(ResultsContainer, { children: [shouldShowDropDown && ((0, jsx_runtime_1.jsxs)(Results, Object.assign({ 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, Object.assign({ 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, Object.assign({ hasSpaceForErrors: true }, { children: !!errors.length && errors.map((err, i) => (0, jsx_runtime_1.jsx)(shared_js_1.Err, { children: err }, `err-${i}`)) }))] })] })));
};
exports.SearchInput = SearchInput;
exports.SearchInput.defaultProps = {
errors: [],
onBlur: id,
onChange: id,
onFocus: id,
results: [],
resultToQuery: id,
search: id,
};
exports.SearchInput.propTypes = {
errors: prop_types_1.default.array,
isInvalid: prop_types_1.default.bool,
NoResults: prop_types_1.default.oneOfType([prop_types_1.default.node, prop_types_1.default.func]),
onBlur: prop_types_1.default.func,
onChange: prop_types_1.default.func,
onFocus: prop_types_1.default.func,
results: prop_types_1.default.array,
resultsMaxHeight: prop_types_1.default.string,
resultToQuery: prop_types_1.default.func.isRequired,
Result: prop_types_1.default.oneOfType([prop_types_1.default.node, prop_types_1.default.func]).isRequired,
search: prop_types_1.default.func.isRequired,
};
exports.default = (0, styled_components_1.default)(exports.SearchInput).withConfig({ componentId: "brc-sc-150ed28" }) ``;
//# sourceMappingURL=search-input.js.map