@etsoo/materialui
Version:
TypeScript Material-UI Implementation
94 lines (93 loc) • 3.86 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useDelayedExecutor } from "@etsoo/react";
import CheckBoxIcon from "@mui/icons-material/CheckBox";
import React from "react";
import { VBox } from "./FlexBox";
import ListItemButton from "@mui/material/ListItemButton";
import List from "@mui/material/List";
import TextField from "@mui/material/TextField";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
/**
* List chooser
* @param props Props
* @returns Component
*/
export function ListChooser(props) {
// Selected ids state
const [selectedIds, setSelectedIds] = React.useState([]);
const selectProps = (id) => ({
selected: selectedIds.includes(id),
onClick: () => {
if (multiple) {
const index = selectedIds.indexOf(id);
if (index === -1)
selectedIds.push(id);
else
selectedIds.splice(index, 1);
setSelectedIds([...selectedIds]);
}
else {
setSelectedIds([id]);
}
}
});
// Destruct
const { conditionField = "title", conditionRenderer = (rq, delayed) => (_jsx(TextField, { autoFocus: true, margin: "dense", name: conditionField, label: title, fullWidth: true, variant: "standard", slotProps: { htmlInput: { maxLength: 128 } }, onChange: (event) => {
Reflect.set(rq, "title", event.target.value);
delayed.call();
} })), itemRenderer = (item, selectProps) => {
const id = item[idField];
const sp = selectProps(id);
const label = typeof labelField === "function"
? labelField(item)
: Reflect.get(item, labelField);
return (_jsx(ListItem, { disableGutters: true, secondaryAction: sp.selected ? _jsx(CheckBoxIcon, { fontSize: "small" }) : undefined, children: _jsx(ListItemButton, { ...sp, children: _jsx(ListItemText, { primary: label }) }) }, `${id}`));
}, idField = "id", labelField = "label", loadData, multiple = false, onItemChange, title, doubleClickEnabled = false, onDoubleClick, ...rest } = props;
// Default minimum height
rest.sx ??= { minHeight: "220px" };
// State
const [items, setItems] = React.useState([]);
// Query request data
const mounted = React.useRef(false);
const rq = React.useRef({});
// Delayed execution
const delayed = useDelayedExecutor(async () => {
const result = await loadData(rq.current);
if (result == null || !mounted.current)
return;
if (!multiple &&
selectedIds.length > 0 &&
!result.some((item) => selectedIds.includes(item[idField]))) {
setSelectedIds([]);
}
setItems(result);
}, 480);
React.useEffect(() => {
if (!mounted.current)
return;
onItemChange(items.filter((item) => selectedIds.includes(item[idField])), selectedIds);
}, [selectedIds]);
React.useEffect(() => {
mounted.current = true;
delayed.call(0);
return () => {
mounted.current = false;
delayed.clear();
};
}, [delayed]);
const onDoubleClickLocal = (event) => {
if (onDoubleClick)
onDoubleClick(event);
if (doubleClickEnabled) {
const button = event.currentTarget
.closest("form")
?.elements.namedItem("okButton");
if (button) {
button.click();
}
}
};
// Layout
return (_jsxs(VBox, { children: [conditionRenderer(rq.current, delayed), _jsx(List, { onDoubleClick: onDoubleClickLocal, disablePadding: true, dense: true, ...rest, children: items.map((item) => itemRenderer(item, selectProps)) })] }));
}