@availity/mui-autocomplete
Version:
Availity MUI Autocomplete Component - part of the @availity/element design system
364 lines (356 loc) • 12.8 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/lib/Autocomplete.tsx
import { forwardRef } from "react";
import {
default as MuiAutocomplete
} from "@mui/material/Autocomplete";
import CircularProgress from "@mui/material/CircularProgress";
import { default as MuiIconButton } from "@mui/material/IconButton";
import { TextField } from "@availity/mui-textfield";
import { SelectDivider, SelectExpandIcon } from "@availity/mui-form-utils";
import { createFilterOptions } from "@mui/material/Autocomplete";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var PopupIndicatorWrapper = forwardRef((props, ref) => /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(SelectDivider, { orientation: "vertical", className: "MuiSelect-avEndAdornmentDivider" }),
/* @__PURE__ */ jsx(MuiIconButton, __spreadProps(__spreadValues({}, props), { ref }))
] }));
var progressSx = { marginRight: ".5rem" };
var LoadingIndicator = () => /* @__PURE__ */ jsx(CircularProgress, { "aria-label": "Loading", size: 20, sx: progressSx });
var Autocomplete = (_a) => {
var _b = _a, {
FieldProps
} = _b, props = __objRest(_b, [
"FieldProps"
]);
const defaultProps = {
fullWidth: true,
size: "small"
};
const resolvedProps = (params) => ({
InputProps: __spreadProps(__spreadValues(__spreadValues({}, params == null ? void 0 : params.InputProps), FieldProps == null ? void 0 : FieldProps.InputProps), {
endAdornment: props.loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
(params == null ? void 0 : params.InputProps.endAdornment) || null,
/* @__PURE__ */ jsx(LoadingIndicator, {})
] }) : (params == null ? void 0 : params.InputProps.endAdornment) || null
}),
inputProps: __spreadProps(__spreadValues({}, params == null ? void 0 : params.inputProps), {
// appease the Level Access scanning tools
"aria-controls": (params == null ? void 0 : params.inputProps["aria-controls"]) || ""
})
});
return /* @__PURE__ */ jsx(
MuiAutocomplete,
__spreadValues(__spreadValues({
renderInput: (params) => {
return /* @__PURE__ */ jsx(TextField, __spreadValues(__spreadValues(__spreadValues({}, params), FieldProps), resolvedProps(params)));
},
popupIcon: /* @__PURE__ */ jsx(SelectExpandIcon, { className: "MuiSelect-avExpandIcon" }),
slotProps: { popupIndicator: { component: PopupIndicatorWrapper } }
}, props), defaultProps)
);
};
// src/lib/AsyncAutocomplete.tsx
import { useState as useState2, useRef, useEffect as useEffect2, useCallback } from "react";
import { useInfiniteQuery } from "@tanstack/react-query";
// src/lib/util.tsx
import { useEffect, useState } from "react";
var useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState("");
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(timer);
};
}, [value]);
return debouncedValue;
};
// src/lib/AsyncAutocomplete.tsx
import { jsx as jsx2 } from "react/jsx-runtime";
var AsyncAutocomplete = (_a) => {
var _b = _a, {
loadOptions,
limit = 50,
queryKey,
ListboxProps,
queryOptions,
watchParams,
debounceTimeout = 350,
FieldProps,
onInputChange,
prependOptions = []
} = _b, rest = __objRest(_b, [
"loadOptions",
"limit",
"queryKey",
"ListboxProps",
"queryOptions",
"watchParams",
"debounceTimeout",
"FieldProps",
"onInputChange",
"prependOptions"
]);
const [inputValue, setInputValue] = useState2("");
const listboxRef = useRef(null);
const setListboxRef = useCallback((node) => {
listboxRef.current = node;
}, []);
const handleInputPropsOnChange = (event) => {
var _a2;
setInputValue(event.target.value);
if ((_a2 = FieldProps == null ? void 0 : FieldProps.InputProps) == null ? void 0 : _a2.onChange) FieldProps.InputProps.onChange(event);
};
const debouncedInput = useDebounce(inputValue, debounceTimeout);
const { isLoading, isFetching, data, hasNextPage, fetchNextPage } = useInfiniteQuery(__spreadValues({
queryKey: [queryKey, limit, debouncedInput, watchParams],
queryFn: (_0) => __async(null, [_0], function* ({ pageParam = 0 }) {
return loadOptions(pageParam, limit, debouncedInput);
}),
staleTime: 1e4,
getNextPageParam: (lastPage) => lastPage.hasMore ? lastPage.offset + limit : void 0
}, queryOptions));
const options = (data == null ? void 0 : data.pages) ? data.pages.map((page) => page.options).flat() : [];
const finalOptions = prependOptions.length > 0 ? [
...prependOptions,
...options.filter(
(option) => !prependOptions.some(
(prepended) => rest.isOptionEqualToValue ? rest.isOptionEqualToValue(option, prepended) : option === prepended
)
)
] : options;
const handleOnInputChange = (event, value, reason) => {
if (reason === "clear") {
setInputValue(event.target.value);
} else if (reason === "blur") {
setInputValue(value);
}
if (onInputChange) onInputChange(event, value, reason);
};
const handleAddingOptions = (event) => __async(null, null, function* () {
const listboxNode = event.currentTarget;
const difference = listboxNode.scrollHeight - (listboxNode.scrollTop + listboxNode.clientHeight);
if (difference <= 5 && !isLoading && !isFetching && hasNextPage) {
fetchNextPage();
}
});
useEffect2(() => {
var _a2;
if (hasNextPage) {
(_a2 = listboxRef.current) == null ? void 0 : _a2.dispatchEvent(new UIEvent("scroll"));
}
}, [data == null ? void 0 : data.pages.length, hasNextPage]);
return /* @__PURE__ */ jsx2(
Autocomplete,
__spreadProps(__spreadValues({}, rest), {
onInputChange: handleOnInputChange,
FieldProps: __spreadProps(__spreadValues({}, FieldProps), {
InputProps: __spreadProps(__spreadValues({}, FieldProps == null ? void 0 : FieldProps.InputProps), {
onChange: handleInputPropsOnChange
})
}),
loading: isFetching,
options: finalOptions,
ListboxProps: __spreadProps(__spreadValues({}, ListboxProps), {
ref: setListboxRef,
onScroll: handleAddingOptions,
onPointerEnter: handleAddingOptions
})
})
);
};
// src/lib/CodesAutocomplete.tsx
import { avCodesApi } from "@availity/api-axios";
import { jsx as jsx3 } from "react/jsx-runtime";
var fetchCodes = (config) => __async(null, null, function* () {
const resp = yield avCodesApi.query(config);
return {
options: resp.data.codes,
hasMore: config.params.offset + config.params.limit < resp.data.totalCount,
offset: config.params.offset
};
});
var handleGetCodesOptionLabel = (option) => [option.code, option.value].filter(Boolean).join(" - ");
var CodesAutocomplete = (_a) => {
var _b = _a, {
apiConfig = {},
queryOptions,
queryKey = "codes-autocomplete",
list,
watchParams
} = _b, rest = __objRest(_b, [
"apiConfig",
"queryOptions",
"queryKey",
"list",
"watchParams"
]);
const handleLoadOptions = (offset, limit, inputValue) => __async(null, null, function* () {
const resp = yield fetchCodes(__spreadProps(__spreadValues({}, apiConfig), {
params: __spreadProps(__spreadValues({}, apiConfig.params), { list, offset, limit, q: inputValue })
}));
return __spreadProps(__spreadValues({}, resp), {
options: resp.options
});
});
return /* @__PURE__ */ jsx3(
AsyncAutocomplete,
__spreadProps(__spreadValues({
getOptionLabel: handleGetCodesOptionLabel,
queryKey,
queryOptions: __spreadValues({ enabled: !!list }, queryOptions),
watchParams: __spreadValues({ list }, watchParams)
}, rest), {
loadOptions: handleLoadOptions
})
);
};
// src/lib/OrganizationAutocomplete.tsx
import { avOrganizationsApi } from "@availity/api-axios";
import qs from "qs";
import { jsx as jsx4 } from "react/jsx-runtime";
var fetchOrgs = (config) => __async(null, null, function* () {
const configWithParamsSerializer = __spreadProps(__spreadValues({}, config), {
paramsSerializer: {
serialize: (params) => qs.stringify(params, { arrayFormat: "repeat" })
}
});
const resp = yield avOrganizationsApi.getOrganizations(configWithParamsSerializer);
return {
options: resp.data.organizations,
hasMore: config.params.offset + config.params.limit < resp.data.totalCount,
offset: config.params.offset
};
});
var handleGetOrgOptionLabel = (org) => org.name;
var OrganizationAutocomplete = (_a) => {
var _b = _a, {
apiConfig = {},
queryKey = "org-autocomplete"
} = _b, rest = __objRest(_b, [
"apiConfig",
"queryKey"
]);
const handleLoadOptions = (offset, limit) => __async(null, null, function* () {
const resp = yield fetchOrgs(__spreadProps(__spreadValues({}, apiConfig), { params: __spreadProps(__spreadValues({ dropdown: true }, apiConfig.params), { offset, limit }) }));
return __spreadProps(__spreadValues({}, resp), {
options: resp.options
});
});
return /* @__PURE__ */ jsx4(
AsyncAutocomplete,
__spreadProps(__spreadValues({
getOptionLabel: handleGetOrgOptionLabel,
queryKey
}, rest), {
loadOptions: handleLoadOptions
})
);
};
// src/lib/ProviderAutocomplete.tsx
import { avProvidersApi } from "@availity/api-axios";
import { jsx as jsx5 } from "react/jsx-runtime";
var fetchProviders = (customerId, config) => __async(null, null, function* () {
const resp = yield avProvidersApi.getProviders(customerId, config);
return {
options: resp.data.providers,
hasMore: config.params.offset + config.params.limit < resp.data.totalCount,
offset: config.params.offset
};
});
var handleGetProviderOptionLabel = (option) => option.uiDisplayName;
var ProviderAutocomplete = (_a) => {
var _b = _a, {
apiConfig = {},
customerId,
queryKey = "prov-autocomplete"
} = _b, rest = __objRest(_b, [
"apiConfig",
"customerId",
"queryKey"
]);
const handleLoadOptions = (offset, limit, inputValue) => __async(null, null, function* () {
const resp = yield fetchProviders(customerId, __spreadProps(__spreadValues({}, apiConfig), {
params: __spreadProps(__spreadValues({}, apiConfig.params), { offset, limit, q: inputValue })
}));
return __spreadProps(__spreadValues({}, resp), {
options: resp.options
});
});
return /* @__PURE__ */ jsx5(
AsyncAutocomplete,
__spreadProps(__spreadValues({
getOptionLabel: handleGetProviderOptionLabel,
queryOptions: { enabled: !!customerId },
queryKey,
watchParams: { customerId }
}, rest), {
loadOptions: handleLoadOptions
})
);
};
export {
AsyncAutocomplete,
Autocomplete,
CodesAutocomplete,
OrganizationAutocomplete,
ProviderAutocomplete,
createFilterOptions,
fetchCodes,
fetchOrgs,
fetchProviders,
handleGetCodesOptionLabel,
handleGetOrgOptionLabel,
handleGetProviderOptionLabel
};