import { useLocal } from "lib/utils/use-local"; import { ReactNode, useCallback, useEffect, useRef } from "react"; import { FieldLocal, FieldProp, FMLocal } from "../typings"; import { BaseFormLocal, default_base_form_local } from "./types"; import { FieldLoading } from "lib/comps/ui/field-loading"; import { editorFormWidth } from "../Form"; import { ConsoleLogWriter } from "drizzle-orm"; export type BaseFormProps = { data: T; className?: string; on_submit?: (form: BaseFormLocal) => Promise | any; children: ReactNode | ((form: BaseFormLocal) => ReactNode); render?: () => void; on_change?: (fm: FMLocal, name: string, new_value: any) => any; is_form?: boolean; name: string; }; export const BaseForm = >( props: BaseFormProps ) => { const { data, children, className, on_submit, render, on_change } = props; const form = useLocal({ ...default_base_form_local, }) as BaseFormLocal; if (render) { form.render = render; } form.submit = useCallback(async () => { if (form.status === "ready") { form.status = "submitting"; form.render(); const result = await on_submit?.(form); setTimeout(() => { form.status = "ready"; form.render(); }, 1000); return result; } }, [on_submit]); form.createArg = (arg) => { const prop: FieldProp = { name: arg.name, on_load: arg.onLoad, sub_type: arg.subType, } as any; if (arg.onChange) prop.on_change = arg.onChange; return prop; }; form.createField = (arg) => { if (form.fields[arg.name]) return form.fields[arg.name]; if (form.fm) form.fm.fields = form.fields; const prop: FieldLocal = { name: arg.name, label: typeof arg.label !== "undefined" ? arg.label : arg.name, render: arg.render || form.render, width: "auto", prefix: arg.prefix, } as any; form.fields[arg.name] = prop; return prop; }; form.createFm = useCallback(() => { if (form.fm) { form.fm.data = data; return form.fm; } let size = "full"; if (form.internal.width > 650) { size = "half"; } form.fm = { data: data, status: "ready", deps: {}, props: { label_mode: "vertical" }, error: { get: () => { return []; }, }, events: { on_change: (n: any, v: any) => { if (on_change && form.fm) { on_change(form.fm, n, v); } }, }, submit: () => on_submit?.(form), size: { field: size }, render: form.render, } as any; return form.fm as any; }, [data]); form.fieldProps = (arg) => { return { fm: form.createFm(), arg: form.createArg(arg), field: form.createField(arg), }; }; const ref = useRef({ el: null as null | HTMLFormElement, timer: null as any, rob: new ResizeObserver(async ([e]) => { let fm = form.fm; if (!fm) { if (ref.current.timer) { return; } ref.current.timer = await new Promise((done) => { const ival = setInterval(() => { if (form.fm) { ref.current.timer = null; clearInterval(ival); done(); } }, 100); }); fm = form.fm; } if (e.contentRect.width > 0 && fm) { fm.size.height = e.contentRect.height; fm.size.width = e.contentRect.width; // if (fm.status === "ready" && !isEditor) fm.status = "resizing"; if (fm.props.layout === "auto" || !fm.props.layout) { if (fm.size.width > 650) { fm.size.field = "half"; } else { fm.size.field = "full"; } } else { if (fm.props.layout === "1-col") fm.size.field = "full"; if (fm.props.layout === "2-col") fm.size.field = "half"; } if (isEditor) { editorFormWidth[props.name] = { w: fm.size.width, f: fm.size.field, }; } fm.status = "ready"; fm.render(); } }), }); useEffect(() => { if (form.internal.width === 0) { setTimeout(() => { form.render(); }, 1000); } }, [data]); if (form.status === "init") { form.status = "ready"; } if (!form.fm) { form.fm = form.createFm(); } const fm = form.fm; if (typeof props.is_form === "boolean") { if (!props.is_form) { if (!form.fm.data) return ; return <>{typeof children === "function" ? children(form) : children}; } } if (form.internal.width === 0) { if (form.internal.init_render > 30) { return <>Failed to render BaseForm; } setTimeout(() => { form.internal.init_render++; form.render(); }, 50); } return (
{ e.preventDefault(); e.stopPropagation(); form.submit(); }} ref={(el) => { if (el) { if (!ref.current.el && fm && fm?.status !== "resizing") { ref.current.el = el; ref.current.rob.observe(el); if (fm.status === "ready") { fm.status = "resizing"; fm.render(); } } } }} className={cx( "form c-flex-1 c-flex c-flex-col c-w-full c-h-full c-relative c-overflow-auto", className )} > {fm?.status === "ready" && ( <>
{ if (el?.offsetWidth) { form.internal.width = el?.offsetWidth; form.createFm(); } }} > {form.internal.width > 0 && ( <>{typeof children === "function" ? children(form) : children} )}
)}
); };