form: fix switch required, add root form error to media settings

This commit is contained in:
dswbx
2025-02-08 13:27:47 +01:00
parent 97b0ff24c8
commit 3fa682bfe1
8 changed files with 74 additions and 21 deletions

View File

@@ -186,7 +186,7 @@ export const Switch = forwardRef<
onChange?: (e: { target: { value: boolean } }) => void;
onCheckedChange?: (checked: boolean) => void;
}
>(({ type, ...props }, ref) => {
>(({ type, required, ...props }, ref) => {
return (
<RadixSwitch.Root
className="relative h-7 w-12 p-[2px] cursor-pointer rounded-full bg-muted border border-primary/10 outline-none data-[state=checked]:bg-primary/75 appearance-none transition-colors hover:bg-muted/80"

View File

@@ -21,6 +21,7 @@ export type FieldwrapperProps = {
wrapper?: "group" | "fieldset";
hidden?: boolean;
children: ReactElement | ReactNode;
errorPlacement?: "top" | "bottom";
};
export function FieldWrapper({
@@ -30,6 +31,7 @@ export function FieldWrapper({
schema,
wrapper,
hidden,
errorPlacement = "bottom",
children
}: FieldwrapperProps) {
const errors = useFormError(name, { strict: true });
@@ -38,12 +40,17 @@ export function FieldWrapper({
const description = schema?.description;
const label = typeof _label !== "undefined" ? _label : schema ? getLabel(name, schema) : name;
const Errors = errors.length > 0 && (
<Formy.ErrorMessage>{errors.map((e) => e.message).join(", ")}</Formy.ErrorMessage>
);
return (
<Formy.Group
error={errors.length > 0}
as={wrapper === "fieldset" ? "fieldset" : "div"}
className={hidden ? "hidden" : "relative"}
>
{errorPlacement === "top" && Errors}
<FieldDebug name={name} schema={schema} required={required} />
{label && (
@@ -73,9 +80,7 @@ export function FieldWrapper({
</div>
</div>
{description && <Formy.Help>{description}</Formy.Help>}
{errors.length > 0 && (
<Formy.ErrorMessage>{errors.map((e) => e.message).join(", ")}</Formy.ErrorMessage>
)}
{errorPlacement === "bottom" && Errors}
</Formy.Group>
);
}

View File

@@ -119,12 +119,12 @@ export function Form<
// @ts-ignore
async function handleSubmit(e: FormEvent<HTMLFormElement>) {
const { data, errors } = validate();
if (onSubmit) {
e.preventDefault();
setFormState((prev) => ({ ...prev, submitting: true }));
try {
const { data, errors } = validate();
if (errors.length === 0) {
await onSubmit(data as Data);
} else {
@@ -136,6 +136,10 @@ export function Form<
}
setFormState((prev) => ({ ...prev, submitting: false }));
return false;
} else if (errors.length > 0) {
e.preventDefault();
onInvalidSubmit?.(errors, data);
return false;
}
}

View File

@@ -28,6 +28,7 @@ export const ObjectField = ({
name={path}
schema={{ ...schema, description: undefined }}
wrapper="fieldset"
errorPlacement="top"
{...wrapperProps}
>
{Object.keys(properties).map((prop) => {

View File

@@ -26,16 +26,24 @@ export function coerce(value: any, schema: JsonSchema, opts?: { required?: boole
return value;
}
const PathFilter = (value: any) => typeof value !== "undefined" && value !== null && value !== "";
export function pathToPointer(path: string) {
return "#/" + (path.includes(".") ? path.split(".").join("/") : path);
const p = path.includes(".") ? path.split(".") : [path];
return (
"#" +
p
.filter(PathFilter)
.map((part) => "/" + part)
.join("")
);
}
export function prefixPointer(pointer: string, prefix: string) {
return pointer.replace("#/", `#/${prefix.length > 0 ? prefix + "/" : ""}`).replace(/\/\//g, "/");
const p = pointer.replace("#", "").split("/");
return "#" + p.map((part, i) => (i === 1 ? prefix : part)).join("/");
}
const PathFilter = (value: any) => typeof value !== "undefined" && value !== null && value !== "";
export function prefixPath(path: string = "", prefix: string | number = "") {
const p = path.includes(".") ? path.split(".") : [path];
return [prefix, ...p].filter(PathFilter).join(".");