feat(mui): kit — Select, StatusChip, CheckboxField, Alert

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-06 21:20:30 +02:00
parent 5855c94b50
commit 05f25931c9
5 changed files with 119 additions and 0 deletions

19
src/admin/ui/Alert.tsx Normal file
View File

@@ -0,0 +1,19 @@
import type { ReactNode } from "react";
import MuiAlert from "@mui/material/Alert";
/** Inline contextual alert (form/section feedback) — distinct from the global toast. */
export default function Alert({
severity = "info",
children,
onClose,
}: {
severity?: "success" | "error" | "warning" | "info";
children: ReactNode;
onClose?: () => void;
}) {
return (
<MuiAlert severity={severity} onClose={onClose} sx={{ borderRadius: 2 }}>
{children}
</MuiAlert>
);
}

26
src/admin/ui/Checkbox.tsx Normal file
View File

@@ -0,0 +1,26 @@
import type { ReactNode } from "react";
import FormControlLabel from "@mui/material/FormControlLabel";
import MuiCheckbox from "@mui/material/Checkbox";
/** Boolean checkbox with a label (distinct from SwitchField's toggle semantics). */
export function CheckboxField({
label,
checked,
onChange,
}: {
label: ReactNode;
checked: boolean;
onChange: (v: boolean) => void;
}) {
return (
<FormControlLabel
control={
<MuiCheckbox
checked={checked}
onChange={(e) => onChange(e.target.checked)}
/>
}
label={label}
/>
);
}

42
src/admin/ui/Select.tsx Normal file
View File

@@ -0,0 +1,42 @@
import MuiTextField, { type TextFieldProps } from "@mui/material/TextField";
import MenuItem from "@mui/material/MenuItem";
export interface SelectOption {
value: string | number;
label: string;
}
type SelectProps = Omit<TextFieldProps, "onChange" | "select" | "value"> & {
value: string | number;
onChange: (value: string) => void;
options?: SelectOption[];
};
/** Dropdown styled like the kit TextField; composes inside <Field>. */
export default function Select({
value,
onChange,
options,
children,
...props
}: SelectProps) {
return (
<MuiTextField
select
size="small"
variant="outlined"
fullWidth
value={value}
onChange={(e) => onChange(e.target.value)}
{...props}
>
{options
? options.map((o) => (
<MenuItem key={o.value} value={o.value}>
{o.label}
</MenuItem>
))
: children}
</MuiTextField>
);
}

View File

@@ -0,0 +1,27 @@
import Chip, { type ChipProps } from "@mui/material/Chip";
type StatusChipProps = Omit<ChipProps, "color"> & {
color?: "default" | "success" | "error" | "warning" | "info";
};
/** Semantic status chip. Pass onClick to make it a clickable toggle. */
export default function StatusChip({
color = "default",
size = "small",
onClick,
sx,
...props
}: StatusChipProps) {
return (
<Chip
color={color}
size={size}
onClick={onClick}
sx={[
{ fontWeight: 600, ...(onClick ? { cursor: "pointer" } : {}) },
...(Array.isArray(sx) ? sx : [sx]),
]}
{...props}
/>
);
}

View File

@@ -7,3 +7,8 @@ export { default as ConfirmDialog } from "./ConfirmDialog";
export { default as DataTable } from "./DataTable"; export { default as DataTable } from "./DataTable";
export type { DataColumn } from "./DataTable"; export type { DataColumn } from "./DataTable";
export { Field, SwitchField } from "./Field"; export { Field, SwitchField } from "./Field";
export { default as Select } from "./Select";
export type { SelectOption } from "./Select";
export { default as StatusChip } from "./StatusChip";
export { CheckboxField } from "./Checkbox";
export { default as Alert } from "./Alert";