深度优化 ui
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
import { useRef, useState, type ComponentProps, type ReactNode } from "react";
|
||||
import { useFormStatus } from "react-dom";
|
||||
|
||||
function FormFields({ children }: { children: ReactNode }) {
|
||||
const { pending } = useFormStatus();
|
||||
return (
|
||||
<fieldset disabled={pending} style={{ display: "contents" }}>
|
||||
{children}
|
||||
</fieldset>
|
||||
);
|
||||
}
|
||||
|
||||
/** Keeps action errors beside the submitted form, without losing entered values. */
|
||||
export function ActionForm({
|
||||
action,
|
||||
children,
|
||||
...props
|
||||
}: Omit<ComponentProps<"form">, "action"> & {
|
||||
action: (data: FormData) => Promise<void>;
|
||||
}) {
|
||||
const preserveValues = useRef(false);
|
||||
const [message, setMessage] = useState("");
|
||||
const [failed, setFailed] = useState(false);
|
||||
return (
|
||||
<form
|
||||
{...props}
|
||||
onReset={(event) => {
|
||||
if (preserveValues.current) event.preventDefault();
|
||||
}}
|
||||
onChange={() => setMessage("")}
|
||||
onKeyDown={(event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
const button = event.currentTarget.querySelector<HTMLButtonElement>(
|
||||
'button[type="submit"]',
|
||||
);
|
||||
if (button && !button.disabled) button.click();
|
||||
}
|
||||
}}
|
||||
action={async (data) => {
|
||||
setMessage("");
|
||||
preserveValues.current = false;
|
||||
try {
|
||||
await action(data);
|
||||
setFailed(false);
|
||||
setMessage("已保存");
|
||||
} catch {
|
||||
preserveValues.current = true;
|
||||
setFailed(true);
|
||||
setMessage("操作失败,请检查输入后重试。填写内容已保留。");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormFields>{children}</FormFields>
|
||||
{message && (
|
||||
<p
|
||||
role={failed ? "alert" : "status"}
|
||||
className={`full-span ${failed ? "error-text" : "muted"}`}
|
||||
>
|
||||
{message}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user