fix lib
This commit is contained in:
parent
8425b4ea95
commit
0338bac9d0
Binary file not shown.
|
|
@ -78,16 +78,18 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ value, className }) => {
|
|||
{cur?.label}
|
||||
</h1>
|
||||
) : (
|
||||
<h1
|
||||
<a
|
||||
href={baseurl(cur.url || "")}
|
||||
className="c-font-normal c-text-xs md:c-text-base hover:c-cursor-pointer hover:c-underline"
|
||||
onClick={(ev) => {
|
||||
ev.preventDefault();
|
||||
if (isEditor) return;
|
||||
if (cur.url) navigate(cur.url || "");
|
||||
if (cur.onClick) cur.onClick(ev);
|
||||
}}
|
||||
>
|
||||
{cur?.label}
|
||||
</h1>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{index !== lastIndex && (
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ export const FilterContent: FC<{
|
|||
>
|
||||
<BaseForm
|
||||
data={filter.data}
|
||||
on_submit={async (form) => {
|
||||
onSubmit={async (form) => {
|
||||
const fm = form.fm;
|
||||
try {
|
||||
if (typeof form.fm?.data === "object") {
|
||||
|
|
|
|||
|
|
@ -35,163 +35,164 @@ export const FilterField: FC<{
|
|||
}, [filter.form]);
|
||||
|
||||
let show_modifier = filter.mode !== "inline";
|
||||
return (
|
||||
<BaseField
|
||||
{...filter.form.fieldProps({
|
||||
name: name || "",
|
||||
label: label || name || "",
|
||||
render: internal.render,
|
||||
prefix: show_modifier
|
||||
? () => (
|
||||
<FieldModifier
|
||||
onChange={(modifier) => {
|
||||
filter.modifiers[name] = modifier;
|
||||
filter.render();
|
||||
filter_window.prasiContext.render();
|
||||
}}
|
||||
modifier={filter.modifiers[name]}
|
||||
type={type}
|
||||
/>
|
||||
)
|
||||
: undefined,
|
||||
onLoad() {
|
||||
return [{ label: "halo", value: "asda" }];
|
||||
},
|
||||
subType: singleOptions.includes(filter.modifiers[name])
|
||||
? "dropdown"
|
||||
: "typeahead",
|
||||
})}
|
||||
>
|
||||
{(field) => {
|
||||
if (type === "search-all") {
|
||||
return (
|
||||
<div className={cx("search-all c-flex items-center")}>
|
||||
<div className="c-pl-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21-4.3-4.3" />
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
type="search"
|
||||
value={field.fm?.data?.[name]}
|
||||
placeholder={field.field.label}
|
||||
onBlur={() => {
|
||||
return null;
|
||||
// return (
|
||||
// <BaseField
|
||||
// {...filter.form.fieldProps({
|
||||
// name: name || "",
|
||||
// label: label || name || "",
|
||||
// render: internal.render,
|
||||
// prefix: show_modifier
|
||||
// ? () => (
|
||||
// <FieldModifier
|
||||
// onChange={(modifier) => {
|
||||
// filter.modifiers[name] = modifier;
|
||||
// filter.render();
|
||||
// filter_window.prasiContext.render();
|
||||
// }}
|
||||
// modifier={filter.modifiers[name]}
|
||||
// type={type}
|
||||
// />
|
||||
// )
|
||||
// : undefined,
|
||||
// onLoad() {
|
||||
// return [{ label: "halo", value: "asda" }];
|
||||
// },
|
||||
// subType: singleOptions.includes(filter.modifiers[name])
|
||||
// ? "dropdown"
|
||||
// : "typeahead",
|
||||
// })}
|
||||
// >
|
||||
// {(field) => {
|
||||
// if (type === "search-all") {
|
||||
// return (
|
||||
// <div className={cx("search-all c-flex items-center")}>
|
||||
// <div className="c-pl-2">
|
||||
// <svg
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// width="14"
|
||||
// height="14"
|
||||
// viewBox="0 0 24 24"
|
||||
// fill="none"
|
||||
// stroke="currentColor"
|
||||
// strokeWidth="2"
|
||||
// strokeLinecap="round"
|
||||
// strokeLinejoin="round"
|
||||
// >
|
||||
// <circle cx="11" cy="11" r="8" />
|
||||
// <path d="m21 21-4.3-4.3" />
|
||||
// </svg>
|
||||
// </div>
|
||||
// <input
|
||||
// type="search"
|
||||
// value={field.fm?.data?.[name]}
|
||||
// placeholder={field.field.label}
|
||||
// onBlur={() => {
|
||||
// // clearTimeout(internal.search_timeout);
|
||||
// // filter.form?.submit();
|
||||
// }}
|
||||
// spellCheck={false}
|
||||
// className="c-flex-1 c-transition-all c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full"
|
||||
// onChange={(e) => {
|
||||
// field.fm.data[name] = e.currentTarget.value;
|
||||
// field.fm.render();
|
||||
// clearTimeout(internal.search_timeout);
|
||||
// internal.search_timeout = setTimeout(() => {
|
||||
// filter.form?.submit();
|
||||
}}
|
||||
spellCheck={false}
|
||||
className="c-flex-1 c-transition-all c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full"
|
||||
onChange={(e) => {
|
||||
field.fm.data[name] = e.currentTarget.value;
|
||||
field.fm.render();
|
||||
clearTimeout(internal.search_timeout);
|
||||
internal.search_timeout = setTimeout(() => {
|
||||
filter.form?.submit();
|
||||
}, 1500);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// }, 1500);
|
||||
// }}
|
||||
// />
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
return (
|
||||
<>
|
||||
{type === "text" && (
|
||||
<FieldTypeInput
|
||||
{...field}
|
||||
prop={{
|
||||
type: "input",
|
||||
sub_type: "text",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{type === "number" && (
|
||||
<>
|
||||
<FieldTypeInput
|
||||
{...field}
|
||||
field={{
|
||||
...field.field,
|
||||
name:
|
||||
filter.modifiers[name] === "between"
|
||||
? name
|
||||
: `${name}_from`,
|
||||
}}
|
||||
prop={{
|
||||
type: "input",
|
||||
sub_type: "number",
|
||||
}}
|
||||
/>
|
||||
{filter.modifiers[name] === "between" && (
|
||||
<FieldTypeInput
|
||||
{...field}
|
||||
field={{ ...field.field, name: `${name}_to` }}
|
||||
prop={{
|
||||
type: "input",
|
||||
sub_type: "number",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{type === "date" && (
|
||||
<>
|
||||
<FieldTypeInput
|
||||
{...field}
|
||||
field={{
|
||||
...field.field,
|
||||
name:
|
||||
filter.modifiers[name] === "between"
|
||||
? name
|
||||
: `${name}_from`,
|
||||
}}
|
||||
prop={{
|
||||
type: "input",
|
||||
sub_type: "date",
|
||||
}}
|
||||
/>
|
||||
{filter.modifiers[name] === "between" && (
|
||||
<FieldTypeInput
|
||||
{...field}
|
||||
field={{ ...field.field, name: `${name}_to` }}
|
||||
prop={{
|
||||
type: "input",
|
||||
sub_type: "date",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{type === "boolean" && (
|
||||
<FieldCheckbox
|
||||
arg={field.arg}
|
||||
field={field.field}
|
||||
fm={field.fm}
|
||||
/>
|
||||
)}
|
||||
{type === "options" && (
|
||||
<>
|
||||
{singleOptions.includes(filter.modifiers[name]) && (
|
||||
<SingleOption {...field} />
|
||||
)}
|
||||
{multiOptions.includes(filter.modifiers[name]) && (
|
||||
<MultiOption {...field} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</BaseField>
|
||||
);
|
||||
// return (
|
||||
// <>
|
||||
// {type === "text" && (
|
||||
// <FieldTypeInput
|
||||
// {...field}
|
||||
// prop={{
|
||||
// type: "input",
|
||||
// sub_type: "text",
|
||||
// }}
|
||||
// />
|
||||
// )}
|
||||
// {type === "number" && (
|
||||
// <>
|
||||
// <FieldTypeInput
|
||||
// {...field}
|
||||
// field={{
|
||||
// ...field.field,
|
||||
// name:
|
||||
// filter.modifiers[name] === "between"
|
||||
// ? name
|
||||
// : `${name}_from`,
|
||||
// }}
|
||||
// prop={{
|
||||
// type: "input",
|
||||
// sub_type: "number",
|
||||
// }}
|
||||
// />
|
||||
// {filter.modifiers[name] === "between" && (
|
||||
// <FieldTypeInput
|
||||
// {...field}
|
||||
// field={{ ...field.field, name: `${name}_to` }}
|
||||
// prop={{
|
||||
// type: "input",
|
||||
// sub_type: "number",
|
||||
// }}
|
||||
// />
|
||||
// )}
|
||||
// </>
|
||||
// )}
|
||||
// {type === "date" && (
|
||||
// <>
|
||||
// <FieldTypeInput
|
||||
// {...field}
|
||||
// field={{
|
||||
// ...field.field,
|
||||
// name:
|
||||
// filter.modifiers[name] === "between"
|
||||
// ? name
|
||||
// : `${name}_from`,
|
||||
// }}
|
||||
// prop={{
|
||||
// type: "input",
|
||||
// sub_type: "date",
|
||||
// }}
|
||||
// />
|
||||
// {filter.modifiers[name] === "between" && (
|
||||
// <FieldTypeInput
|
||||
// {...field}
|
||||
// field={{ ...field.field, name: `${name}_to` }}
|
||||
// prop={{
|
||||
// type: "input",
|
||||
// sub_type: "date",
|
||||
// }}
|
||||
// />
|
||||
// )}
|
||||
// </>
|
||||
// )}
|
||||
// {type === "boolean" && (
|
||||
// <FieldCheckbox
|
||||
// arg={field.arg}
|
||||
// field={field.field}
|
||||
// fm={field.fm}
|
||||
// />
|
||||
// )}
|
||||
// {type === "options" && (
|
||||
// <>
|
||||
// {singleOptions.includes(filter.modifiers[name]) && (
|
||||
// <SingleOption {...field} />
|
||||
// )}
|
||||
// {multiOptions.includes(filter.modifiers[name]) && (
|
||||
// <MultiOption {...field} />
|
||||
// )}
|
||||
// </>
|
||||
// )}
|
||||
// </>
|
||||
// );
|
||||
// }}
|
||||
// </BaseField>
|
||||
// );
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
import { ReactNode } from "react";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../typings";
|
||||
import { FieldLoading } from "lib/comps/ui/field-loading";
|
||||
import { Label } from "../field/Label";
|
||||
import { FieldLoading } from "../../ui/field-loading";
|
||||
import { FMLocal, FieldLocal, FieldProp } from "../typings";
|
||||
import { useField } from "../utils/use-field";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
export const BaseField = (prop: {
|
||||
field: FieldLocal;
|
||||
fm: FMLocal;
|
||||
arg: FieldProp;
|
||||
children: (arg: {
|
||||
field: FieldLocal;
|
||||
fm: FMLocal;
|
||||
arg: FieldProp;
|
||||
}) => ReactNode;
|
||||
}) => {
|
||||
const { field, fm, arg } = prop;
|
||||
const w = field.width;
|
||||
export const BaseField = (
|
||||
arg: FieldProp & {
|
||||
children?: (arg: { fm: FMLocal; field: FieldLocal }) => ReactNode;
|
||||
}
|
||||
) => {
|
||||
const field = useField(arg);
|
||||
const fm = arg.fm;
|
||||
arg.fm.fields[arg.name] = field;
|
||||
|
||||
const w = field.width || "auto";
|
||||
const prefix =
|
||||
typeof field.prefix === "function"
|
||||
? field.prefix()
|
||||
|
|
@ -29,9 +28,7 @@ export const BaseField = (prop: {
|
|||
: null;
|
||||
const name = field.name;
|
||||
const errors = fm.error.get(name);
|
||||
|
||||
const showlabel = arg.show_label || "y";
|
||||
|
||||
const disabled =
|
||||
typeof field.disabled === "function" ? field.disabled() : field.disabled;
|
||||
const show =
|
||||
|
|
@ -54,8 +51,8 @@ export const BaseField = (prop: {
|
|||
css`
|
||||
padding: 5px 0px 0px 10px;
|
||||
`,
|
||||
w === "auto" && fm.size.field === "full" && "c-w-full",
|
||||
w === "auto" && fm.size.field === "half" && "c-w-1/2",
|
||||
w === "auto" && fm.size?.field === "full" && "c-w-full",
|
||||
w === "auto" && fm.size?.field === "half" && "c-w-1/2",
|
||||
w === "full" && "c-w-full",
|
||||
w === "¾" && "c-w-3/4",
|
||||
w === "½" && "c-w-1/2",
|
||||
|
|
@ -65,7 +62,6 @@ export const BaseField = (prop: {
|
|||
css`
|
||||
.field-outer {
|
||||
border: 1px solid ${disabled ? "#ececeb" : "#cecece"};
|
||||
|
||||
&.focused {
|
||||
border: 1px solid #1c4ed8;
|
||||
outline: 1px solid #1c4ed8;
|
||||
|
|
@ -95,7 +91,9 @@ export const BaseField = (prop: {
|
|||
>
|
||||
<div
|
||||
className={cx(
|
||||
!["toggle", "button", "radio", "checkbox"].includes(arg.sub_type)
|
||||
!["toggle", "button", "radio", "checkbox"].includes(
|
||||
arg.sub_type || ""
|
||||
)
|
||||
? cx(
|
||||
"field-outer c-overflow-hidden c-flex-1 c-flex c-flex-row c-text-sm c-bg-white",
|
||||
"c-rounded "
|
||||
|
|
@ -139,7 +137,8 @@ export const BaseField = (prop: {
|
|||
field.disabled && "c-pointer-events-none"
|
||||
)}
|
||||
>
|
||||
{prop.children(prop)}
|
||||
{typeof arg.children === "function" &&
|
||||
arg.children({ fm, field })}
|
||||
</div>
|
||||
)}
|
||||
{suffix && suffix !== "" ? (
|
||||
|
|
@ -153,14 +152,11 @@ export const BaseField = (prop: {
|
|||
<></>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* {JSON.stringify(errors)} */}
|
||||
{errors.length > 0 && (
|
||||
<div
|
||||
className={cx(
|
||||
"field-error c-p-2 c-pl-0 c-text-xs c-text-red-600",
|
||||
field.desc && "c-pt-0",
|
||||
|
||||
css`
|
||||
padding-left: 0px !important;
|
||||
`
|
||||
|
|
|
|||
|
|
@ -1,143 +1,125 @@
|
|||
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 { ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { Toaster } from "sonner";
|
||||
import { editorFormWidth } from "../Form";
|
||||
import { ConsoleLogWriter } from "drizzle-orm";
|
||||
import { FMLocal } from "../typings";
|
||||
import { createFm } from "./utils/create-fm";
|
||||
import { DivForm } from "./utils/DivForm";
|
||||
|
||||
export type BaseFormProps<T> = {
|
||||
name: string;
|
||||
data: T;
|
||||
className?: string;
|
||||
on_submit?: (form: BaseFormLocal<T>) => Promise<any> | any;
|
||||
children: ReactNode | ((form: BaseFormLocal<T>) => ReactNode);
|
||||
render?: () => void;
|
||||
on_change?: (fm: FMLocal, name: string, new_value: any) => any;
|
||||
is_form?: boolean;
|
||||
name: string;
|
||||
onField?: () => void;
|
||||
onSubmit?: (arg: { fm: FMLocal }) => Promise<boolean> | boolean;
|
||||
onChange?: (fm: FMLocal, name: string, new_value: any) => any;
|
||||
children: ReactNode | ((arg: { fm: FMLocal }) => ReactNode);
|
||||
tag?: "form" | "div";
|
||||
};
|
||||
export const BaseForm = <T extends Record<string, any>>(
|
||||
props: BaseFormProps<T>
|
||||
) => {
|
||||
const { data, children, className, on_submit, render, on_change } = props;
|
||||
const form = useLocal({
|
||||
...default_base_form_local,
|
||||
}) as BaseFormLocal<T>;
|
||||
|
||||
if (render) {
|
||||
form.render = render;
|
||||
}
|
||||
export const BaseForm = <T extends Record<string, any>>({
|
||||
tag,
|
||||
data,
|
||||
children,
|
||||
name,
|
||||
onSubmit,
|
||||
className,
|
||||
}: BaseFormProps<T>) => {
|
||||
const render = useState({})[1];
|
||||
const local = useRef({
|
||||
fm: null as null | FMLocal,
|
||||
el: null as null | HTMLFormElement,
|
||||
rob: new ResizeObserver(async ([e]) => {
|
||||
measureSize(name, fm, e.target as HTMLFormElement);
|
||||
}),
|
||||
}).current;
|
||||
|
||||
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 [];
|
||||
if (!local.fm) {
|
||||
local.fm = createFm({
|
||||
data,
|
||||
onSubmit,
|
||||
render() {
|
||||
render({});
|
||||
},
|
||||
},
|
||||
events: {
|
||||
on_change: (n: any, v: any) => {
|
||||
if (on_change && form.fm) {
|
||||
on_change(form.fm, n, v);
|
||||
});
|
||||
}
|
||||
useEffect(() => {
|
||||
if (local.fm && local.fm.data !== data) {
|
||||
for (const k of Object.keys(local.fm.data)) {
|
||||
delete local.fm.data[k];
|
||||
}
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
local.fm.data[k] = v;
|
||||
}
|
||||
console.log(local.fm.data, data)
|
||||
local.fm.render();
|
||||
}
|
||||
},
|
||||
},
|
||||
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 fm = local.fm;
|
||||
|
||||
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;
|
||||
let child = null;
|
||||
if (children) {
|
||||
if (typeof children === "function") {
|
||||
child = children({ fm: local.fm });
|
||||
} else {
|
||||
child = children;
|
||||
}
|
||||
ref.current.timer = await new Promise<void>((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 (document.getElementsByClassName("prasi-toaster").length === 0) {
|
||||
const elemDiv = document.createElement("div");
|
||||
elemDiv.className = "prasi-toaster";
|
||||
document.body.appendChild(elemDiv);
|
||||
}
|
||||
const toaster_el = document.getElementsByClassName("prasi-toaster")[0];
|
||||
|
||||
// if (fm.status === "ready" && !isEditor) fm.status = "resizing";
|
||||
return (
|
||||
<DivForm
|
||||
tag={tag || "form"}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
if (!local.el && fm) {
|
||||
local.el = el;
|
||||
measureSize(name, fm, el);
|
||||
local.rob.observe(el);
|
||||
}
|
||||
}
|
||||
}}
|
||||
className={cx(
|
||||
"form c-flex-1 c-flex c-flex-col c-w-full c-h-full c-relative c-overflow-auto",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{toaster_el && createPortal(<Toaster cn={cx} />, toaster_el)}
|
||||
|
||||
if (fm.props.layout === "auto" || !fm.props.layout) {
|
||||
<div
|
||||
className={cx(
|
||||
"form-inner c-flex-1 c-flex c-flex-row c-flex-wrap c-items-start c-content-start c-absolute c-inset-0",
|
||||
css`
|
||||
padding-right: 10px;
|
||||
`
|
||||
)}
|
||||
>
|
||||
{fm.size && fm.size.width > 0 && <>{child}</>}
|
||||
</div>
|
||||
</DivForm>
|
||||
);
|
||||
};
|
||||
|
||||
const measureSize = (name: string, fm: FMLocal, e: HTMLFormElement) => {
|
||||
if (!fm.size) {
|
||||
fm.size = { field: "full", width: 0, height: 0 };
|
||||
}
|
||||
|
||||
if (e.clientWidth > 0 && fm && fm.size) {
|
||||
fm.size.height = e.clientHeight;
|
||||
fm.size.width = e.clientWidth;
|
||||
|
||||
if (fm.props?.layout === "auto" || !fm.props?.layout) {
|
||||
if (fm.size.width > 650) {
|
||||
fm.size.field = "half";
|
||||
} else {
|
||||
|
|
@ -149,7 +131,7 @@ export const BaseForm = <T extends Record<string, any>>(
|
|||
}
|
||||
|
||||
if (isEditor) {
|
||||
editorFormWidth[props.name] = {
|
||||
editorFormWidth[name] = {
|
||||
w: fm.size.width,
|
||||
f: fm.size.field,
|
||||
};
|
||||
|
|
@ -158,88 +140,4 @@ export const BaseForm = <T extends Record<string, any>>(
|
|||
|
||||
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 <FieldLoading />;
|
||||
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 (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
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" && (
|
||||
<>
|
||||
<div
|
||||
className={cx(
|
||||
"form-inner c-flex-1 c-flex c-flex-row c-flex-wrap c-items-start c-content-start c-absolute c-inset-0",
|
||||
css`
|
||||
padding-right: 10px;
|
||||
`
|
||||
)}
|
||||
ref={(el) => {
|
||||
if (el?.offsetWidth) {
|
||||
form.internal.width = el?.offsetWidth;
|
||||
form.createFm();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{form.internal.width > 0 && (
|
||||
<>{typeof children === "function" ? children(form) : children}</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,4 +34,5 @@ export type BaseFormLocal<T> = Omit<typeof default_base_form_local, "data"> & {
|
|||
};
|
||||
submit: () => Promise<any> | any;
|
||||
render: () => void;
|
||||
init: boolean;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { forwardRef } from "react";
|
||||
|
||||
export const DivForm = forwardRef<
|
||||
HTMLFormElement,
|
||||
React.DetailedHTMLProps<
|
||||
React.HTMLAttributes<HTMLFormElement>,
|
||||
HTMLFormElement
|
||||
> & { tag: "form" | "div" }
|
||||
>((arg, ref) => {
|
||||
if (arg.tag === "div") {
|
||||
const props = { ...arg } as any;
|
||||
if (props.onSubmit) delete props.onSubmit;
|
||||
return (
|
||||
<div {...props} ref={ref}>
|
||||
{arg.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<form {...arg} ref={ref}>
|
||||
{arg?.children}
|
||||
</form>
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import { FMLocal } from "lib/exports";
|
||||
import { formError } from "../../utils/error";
|
||||
|
||||
export const createFm = (arg: {
|
||||
data: any;
|
||||
onSubmit?: (arg: { fm: FMLocal }) => Promise<boolean> | boolean;
|
||||
render: () => void;
|
||||
}) => {
|
||||
const fm = {
|
||||
data: arg.data,
|
||||
fields: {},
|
||||
render: arg.render,
|
||||
} as FMLocal;
|
||||
|
||||
fm.submit = async () => {
|
||||
if (arg.onSubmit) {
|
||||
await arg.onSubmit({ fm });
|
||||
}
|
||||
return true;
|
||||
};
|
||||
fm.error = formError(fm);
|
||||
|
||||
return fm;
|
||||
};
|
||||
|
|
@ -134,7 +134,7 @@ export const FieldInput: FC<{
|
|||
return (
|
||||
<div
|
||||
className={cx(
|
||||
!["toggle", "button", "radio", "checkbox"].includes(arg.sub_type)
|
||||
!["toggle", "button", "radio", "checkbox"].includes(arg.sub_type || "")
|
||||
? cx(
|
||||
"field-outer c-overflow-hidden c-flex-1 c-flex c-flex-row c-text-sm c-bg-white",
|
||||
"c-rounded "
|
||||
|
|
@ -182,7 +182,7 @@ export const FieldInput: FC<{
|
|||
field.focused && "focused",
|
||||
arg.sub_type !== "upload" && disabled && "c-pointer-events-none",
|
||||
disabled &&
|
||||
!["checkbox"].includes(arg.sub_type) &&
|
||||
!["checkbox"].includes(arg.sub_type || '') &&
|
||||
" c-bg-gray-50"
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export const Label: FC<{ field: FieldLocal; fm: FMLocal; arg: FieldProp }> = ({
|
|||
"c-mt-3 c-w-full c-justify-between"
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<div className="c-flex c-items-center">
|
||||
<span className={cx(errors.length > 0 && `c-text-red-600`)}>
|
||||
{field.label}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ type FieldType =
|
|||
export type FieldProp = {
|
||||
name: string;
|
||||
label: string;
|
||||
label_action: ReactNode;
|
||||
label_action?: ReactNode;
|
||||
desc?: string;
|
||||
props?: any;
|
||||
mask?: string;
|
||||
|
|
@ -57,7 +57,7 @@ export type FieldProp = {
|
|||
cover_text: string;
|
||||
cover_field: string;
|
||||
};
|
||||
link: {
|
||||
link?: {
|
||||
text:
|
||||
| string
|
||||
| ((arg: {
|
||||
|
|
@ -68,60 +68,60 @@ export type FieldProp = {
|
|||
params: (field: FieldLocal) => { where: any } | Promise<{ where: any }>;
|
||||
};
|
||||
fm: FMLocal;
|
||||
type: FieldType | (() => FieldType);
|
||||
required: ("y" | "n") | (() => "y" | "n");
|
||||
type?: FieldType | (() => FieldType);
|
||||
required?: ("y" | "n") | (() => "y" | "n");
|
||||
field_ref?: (ref: any) => void;
|
||||
required_msg: (name: string) => string | ReactElement;
|
||||
on_change: (arg: {
|
||||
required_msg?: (name: string) => string | ReactElement;
|
||||
on_change?: (arg: {
|
||||
value: any;
|
||||
name: string;
|
||||
fm: any;
|
||||
}) => void | Promise<void>;
|
||||
PassProp: any;
|
||||
disabled: ("y" | "n") | (() => true | false);
|
||||
child: any;
|
||||
selection: "single" | "multi";
|
||||
prefix: any;
|
||||
suffix: any;
|
||||
width: "auto" | "full" | "¾" | "½" | "⅓" | "¼";
|
||||
_item: PrasiItem;
|
||||
__props: any;
|
||||
PassProp?: any;
|
||||
disabled?: ("y" | "n") | (() => true | false);
|
||||
child?: any;
|
||||
selection?: "single" | "multi";
|
||||
prefix?: any;
|
||||
suffix?: any;
|
||||
width?: "auto" | "full" | "¾" | "½" | "⅓" | "¼";
|
||||
_item?: PrasiItem;
|
||||
__props?: any;
|
||||
custom?: () => CustomField;
|
||||
on_load: (
|
||||
on_load?: (
|
||||
arg?: any
|
||||
) =>
|
||||
| { value: string; label: string }[]
|
||||
| Promise<{ value: string; label: string }[]>;
|
||||
opt_get_label: (
|
||||
opt_get_label?: (
|
||||
row: any,
|
||||
mode: "list" | "label",
|
||||
opt?: { next?: any; prev?: any }
|
||||
) => string;
|
||||
opt_get_value: (arg: {
|
||||
opt_get_value?: (arg: {
|
||||
options: { label: string; value: string; item?: string }[];
|
||||
fm: FMLocal;
|
||||
name: string;
|
||||
type: string;
|
||||
}) => any;
|
||||
tbl_show_header?: "y" | "n";
|
||||
opt_set_value: (arg: {
|
||||
opt_set_value?: (arg: {
|
||||
selected: string[];
|
||||
options: { label: string; value: string; item?: string }[];
|
||||
fm: FMLocal;
|
||||
name: string;
|
||||
type: string;
|
||||
}) => any;
|
||||
opt_selected: (arg: {
|
||||
opt_selected?: (arg: {
|
||||
item: { value: string; label: string; item?: any };
|
||||
current: any;
|
||||
options: { value: string; label: string; item?: any }[];
|
||||
}) => boolean;
|
||||
on_init: (arg: { field: any; name: string }) => void;
|
||||
pk: string;
|
||||
sub_type: string;
|
||||
placeholder: string;
|
||||
show_label: boolean | "y" | "n";
|
||||
msg_error: string;
|
||||
on_init?: (arg: { field: any; name: string }) => void;
|
||||
pk?: string;
|
||||
sub_type?: string;
|
||||
placeholder?: string;
|
||||
show_label?: boolean | "y" | "n";
|
||||
msg_error?: string;
|
||||
gen_table?: string;
|
||||
gen_fields?: string;
|
||||
model_upload?: "upload" | "import";
|
||||
|
|
@ -154,8 +154,8 @@ export type FMInternal = {
|
|||
internal: {
|
||||
original_render?: () => void;
|
||||
};
|
||||
props: Exclude<FMProps, "body" | "PassProp">;
|
||||
size: {
|
||||
props?: Exclude<FMProps, "body" | "PassProp">;
|
||||
size?: {
|
||||
width: number;
|
||||
height: number;
|
||||
field: "full" | "half";
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ export const useField = (
|
|||
const label = typeof arg.label === "string" ? arg.label : arg.label();
|
||||
|
||||
const required =
|
||||
typeof arg.required === "string" ? arg.required === "y" : arg.required();
|
||||
(typeof arg.required === "string"
|
||||
? arg.required === "y"
|
||||
: arg.required?.()) || "n";
|
||||
const update_field = {
|
||||
name: name.replace(/\s*/gi, ""),
|
||||
label: label,
|
||||
|
|
@ -43,10 +45,9 @@ export const useField = (
|
|||
min_date: arg.min_date,
|
||||
table_fields: [],
|
||||
disabled_search: arg.disabled_search,
|
||||
hidden: arg.show
|
||||
hidden: arg.show,
|
||||
};
|
||||
|
||||
|
||||
if (field.status === "init" || isEditor) {
|
||||
for (const [k, v] of Object.entries(update_field)) {
|
||||
(field as any)[k] = v;
|
||||
|
|
@ -67,7 +68,5 @@ export const useField = (
|
|||
|
||||
field.prop = arg as any;
|
||||
|
||||
if(field.name === "complete_description") console.log(update_field);
|
||||
if(field.name === "complete_description") console.log(field);
|
||||
return field;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue