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