UNPKG

@etsoo/materialui

Version:

TypeScript Material-UI Implementation

140 lines (139 loc) 7.53 kB
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 })] })] })); }