@etsoo/materialui
Version:
TypeScript Material-UI Implementation
136 lines (135 loc) • 7.26 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComboBoxMultiple = ComboBoxMultiple;
const jsx_runtime_1 = require("react/jsx-runtime");
const shared_1 = require("@etsoo/shared");
const react_1 = __importDefault(require("react"));
const shared_2 = require("@etsoo/shared");
const react_2 = require("@etsoo/react");
const CheckBoxOutlineBlank_1 = __importDefault(require("@mui/icons-material/CheckBoxOutlineBlank"));
const CheckBox_1 = __importDefault(require("@mui/icons-material/CheckBox"));
const SearchField_1 = require("./SearchField");
const InputField_1 = require("./InputField");
const ReactApp_1 = require("./app/ReactApp");
const Checkbox_1 = __importDefault(require("@mui/material/Checkbox"));
const Autocomplete_1 = __importDefault(require("@mui/material/Autocomplete"));
const icon = (0, jsx_runtime_1.jsx)(CheckBoxOutlineBlank_1.default, { fontSize: "small" });
const checkedIcon = (0, jsx_runtime_1.jsx)(CheckBox_1.default, { fontSize: "small" });
/**
* ComboBox multiple
* @param props Props
* @returns Component
*/
function ComboBoxMultiple(props) {
// Global app
const app = (0, ReactApp_1.useAppContext)();
// Labels
const labels = app?.getLabels("noOptions", "loading");
// Destruct
const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = (props, option, { selected }) => ((0, jsx_runtime_1.jsxs)("li", { ...props, children: [(0, jsx_runtime_1.jsx)(Checkbox_1.default, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] })), getOptionLabel = (option) => `${option[labelField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, ...rest } = props;
// Value input ref
const inputRef = react_1.default.createRef();
// Options state
const [localOptions, setOptions] = react_1.default.useState(options ?? []);
const isMounted = react_1.default.useRef(true);
// Local default value
const localValue = idValue != null
? localOptions.filter((o) => o[idField] === idValue)
: idValues != null
? localOptions.filter((o) => idValues?.includes(o[idField]))
: defaultValue?.concat() ?? value?.concat();
// State
// null for controlled
const [stateValue, setStateValue] = react_1.default.useState(null);
react_1.default.useEffect(() => {
setStateValue(localValue ?? []);
}, [localValue]);
// When options change
// [options] will cause infinite loop
const propertyWay = loadData == null;
react_1.default.useEffect(() => {
if (propertyWay && options != null) {
setOptions(options);
if (stateValue != null) {
if (Array.isArray(stateValue)) {
const newState = stateValue.filter((item) => options.some((option) => option[idField] === item[idField]));
setStateValue(newState);
}
else if (!options.some((option) => option[idField] === stateValue[idField])) {
setStateValue(null);
}
}
}
}, [options, propertyWay]);
// Add readOnly
const addReadOnly = (params) => {
if (readOnly != null) {
Object.assign(params, { readOnly });
}
Object.assign(params.inputProps, { "data-reset": inputReset });
if (dataReadonly) {
params.inputProps.onKeyDown = (event) => {
if (shared_1.Keyboard.isTypingContent(event.key)) {
event.preventDefault();
}
};
}
// https://stackoverflow.com/questions/15738259/disabling-chrome-autofill
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html
Object.assign(params.inputProps, { autoComplete: inputAutoComplete });
return params;
};
const getValue = (value) => {
if (value == null)
return "";
return value.map((item) => item[idField]).join(",");
};
const setInputValue = (value) => {
// Set state
setStateValue(value);
// Input value
const input = inputRef.current;
if (input) {
// Update value
const newValue = getValue(value);
if (newValue !== input.value) {
// Different value, trigger change event
react_2.ReactUtils.triggerChange(input, newValue, false);
}
}
};
react_1.default.useEffect(() => {
if (propertyWay || loadData == null)
return;
loadData().then((result) => {
if (result == null || !isMounted.current)
return;
if (onLoadData)
onLoadData(result);
if (autoAddBlankItem) {
shared_2.Utils.addBlankItem(result, idField, labelField);
}
setOptions(result);
});
}, [propertyWay, autoAddBlankItem, idField, labelField]);
react_1.default.useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
// Layout
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("input", { ref: inputRef, "data-reset": inputReset ?? true, type: "text", style: { display: "none" }, name: name, value: getValue(stateValue), readOnly: true, onChange: inputOnChange }), (0, jsx_runtime_1.jsx)(Autocomplete_1.default, { value: stateValue == null
? []
: Array.isArray(stateValue)
? stateValue
: [stateValue], disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, multiple: true, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
// Set value
setInputValue(value.concat());
// Custom
if (onChange != null)
onChange(event, value, reason, details);
}, openOnFocus: openOnFocus, sx: sx, renderInput: (params) => search ? ((0, jsx_runtime_1.jsx)(SearchField_1.SearchField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })) : ((0, jsx_runtime_1.jsx)(InputField_1.InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })), options: localOptions, renderOption: renderOption, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })] }));
}