@etsoo/materialui
Version:
TypeScript Material-UI Implementation
140 lines (139 loc) • 7.53 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import Button from "@mui/material/Button";
import Chip from "@mui/material/Chip";
import React from "react";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
import AddIcon from "@mui/icons-material/Add";
import IconButton from "@mui/material/IconButton";
import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "@mui/material/Checkbox";
import TextField from "@mui/material/TextField";
import { HBox, VBox } from "./FlexBox";
import { useRequiredAppContext } from "./app/ReactApp";
import FormLabel from "@mui/material/FormLabel";
import { DnDList } from "./DnDList";
function ButtonPopupList(props) {
// Destruct
const { addSplitter = /\s*[,;]\s*/, value = [], items, labelField, labelFormatter, labels, onAdd, onValueChange } = props;
// Methods
const dndRef = React.createRef();
// Refs
const inputRef = React.useRef(null);
const tempSelectedIds = React.useRef([]);
// State
const [selectedIds, setSelectedIds] = React.useState([]);
const setSelectedIdsHandler = (ids) => {
tempSelectedIds.current = ids;
setSelectedIds(ids);
};
React.useEffect(() => {
// Sort items by ids for first load
items.sortByProperty("id", value);
// Set selected ids
setSelectedIdsHandler([...value]);
}, [value]);
return (_jsxs(VBox, { gap: 2, children: [_jsx(DnDList, { component: Grid, componentProps: { container: true, spacing: 0 }, items: items, labelField: labelField, onFormChange: (items) => {
const ids = items
.filter((item) => tempSelectedIds.current.includes(item.id))
.map((item) => item.id);
onValueChange(ids);
}, itemRenderer: (item, index, nodeRef, actionNodeRef) => (_jsxs(Grid, { size: { xs: 12, md: 6, lg: 4 }, display: "flex", justifyContent: "flex-start", alignItems: "center", gap: 1, ...nodeRef, children: [_jsx(IconButton, { style: { cursor: "move" }, size: "small", title: labels?.dragIndicator, ...actionNodeRef, children: _jsx(DragIndicatorIcon, {}) }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { name: "item", value: item.id, checked: selectedIds.includes(item.id), onChange: (e) => {
const checked = e.target.checked;
const newIds = [
...selectedIds.toggleItem(item.id, checked)
];
setSelectedIdsHandler(newIds);
} }), label: `${index + 1}. ${labelFormatter(item)}` })] })), height: 200, mRef: dndRef }), onAdd && (_jsxs(HBox, { gap: 1, children: [_jsx(TextField, { variant: "outlined", label: labels?.more, fullWidth: true, inputRef: inputRef }), _jsx(Button, { sx: { width: "120px" }, variant: "contained", startIcon: _jsx(AddIcon, {}), size: "small", onClick: async () => {
if (inputRef.current == null)
return;
const input = inputRef.current.value.trim();
if (input === "") {
inputRef.current.focus();
return;
}
const items = dndRef.current?.getItems() ?? [];
const inputIds = input
.split(addSplitter)
.filter((id) => !items.some((item) => item.id == id));
if (inputIds.length === 0) {
inputRef.current.focus();
return;
}
const result = await onAdd(inputIds);
if (result === false) {
inputRef.current.focus();
return;
}
dndRef.current?.addItems(result);
inputRef.current.value = "";
inputRef.current.focus();
}, children: labels?.add })] }))] }));
}
export function ButtonPopupCheckbox(props) {
// App
const app = useRequiredAppContext();
// Destruct
const { addSplitter, value = [], inputName, label, labelEnd, labelFormatter = (data) => {
if (labelField in data) {
return data[labelField];
}
return data.id.toString();
}, labelField, labels = {}, loadData, onAdd, onValueChange, popupTitle = label, popupMessage, required = false, sx = { gap: 1, justifyContent: "flex-start", minHeight: "56px" }, variant = "outlined", ...rest } = props;
// Default labels
if (!labels.add)
labels.add = app.get("add");
if (!labels.dragIndicator)
labels.dragIndicator = app.get("dragIndicator");
if (!labels.more)
labels.more = app.get("more");
// State
const [items, setItems] = React.useState([]);
const [selectedIds, setSelectedIds] = React.useState();
React.useEffect(() => {
if (typeof loadData === "function") {
// Load data
loadData().then((data) => {
if (data != null) {
setItems(data);
}
});
}
else {
setItems(loadData);
}
}, [loadData]);
React.useEffect(() => {
// Set selected ids
setSelectedIds(value);
}, [value]);
// Selected ids
const tempSelectedIds = React.useRef();
// Click handler
const clickHandler = () => {
app.showInputDialog({
title: popupTitle,
message: popupMessage,
callback: (form) => {
if (form == null || tempSelectedIds.current == null)
return;
const ids = tempSelectedIds.current;
setSelectedIds(ids);
onValueChange?.(ids);
},
inputs: (_jsx(ButtonPopupList, { addSplitter: addSplitter, value: selectedIds, items: items, labelFormatter: labelFormatter, labelField: labelField, labels: labels, onAdd: onAdd, onValueChange: (ids) => {
tempSelectedIds.current = ids;
} })),
fullScreen: app.smDown
});
};
return (_jsxs(React.Fragment, { children: [_jsx("input", { type: "text", style: { position: "absolute", opacity: 0, width: 0 }, name: inputName, required: required, defaultValue: selectedIds?.join(",") }), _jsxs(Button, { variant: variant, sx: sx, onClick: () => clickHandler(), ...rest, disabled: !items || items.length === 0, children: [label && (_jsx(FormLabel, { required: required, sx: { fontSize: (theme) => theme.typography.body2.fontSize }, children: label })), selectedIds?.map((id) => {
const item = items.find((item) => item.id === id);
if (item == null)
return null;
return (_jsx(Chip, { sx: {
pointerEvents: "none"
}, size: "small", label: labelFormatter(item) }, id));
}), labelEnd && _jsx(Typography, { variant: "caption", children: labelEnd })] })] }));
}