fix
This commit is contained in:
parent
72bcba5bb5
commit
26c1402bd1
|
|
@ -1,14 +1,12 @@
|
||||||
import { useLocal } from "@/utils/use-local";
|
import { useLocal } from "@/utils/use-local";
|
||||||
import { FC, Fragment, useEffect, useRef } from "react";
|
import get from "lodash.get";
|
||||||
import { FMInternal, FMProps } from "./typings";
|
import { FC, useRef } from "react";
|
||||||
import { formReload } from "./utils/reload";
|
|
||||||
import { formInit } from "./utils/init";
|
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import { Toaster } from "sonner";
|
import { Toaster } from "sonner";
|
||||||
import get from "lodash.get";
|
import { FMInternal, FMProps } from "./typings";
|
||||||
import { Field } from "./field/Field";
|
|
||||||
import { getProp } from "../../..";
|
|
||||||
import { editorFormData } from "./utils/ed-data";
|
import { editorFormData } from "./utils/ed-data";
|
||||||
|
import { formInit } from "./utils/init";
|
||||||
|
import { formReload } from "./utils/reload";
|
||||||
|
|
||||||
const editorFormWidth = {} as Record<string, { w: number; f: any }>;
|
const editorFormWidth = {} as Record<string, { w: number; f: any }>;
|
||||||
|
|
||||||
|
|
@ -35,6 +33,7 @@ export const Form: FC<FMProps> = (props) => {
|
||||||
done: [],
|
done: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
field_def: {},
|
||||||
props: {} as any,
|
props: {} as any,
|
||||||
size: {
|
size: {
|
||||||
width: editorFormWidth[props.item.id]
|
width: editorFormWidth[props.item.id]
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ export const Field: FC<FieldProp> = (arg) => {
|
||||||
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-1/2",
|
w === "½" && "c-w-1/2",
|
||||||
w === "⅓" && "c-w-1/3",
|
w === "⅓" && "c-w-1/3",
|
||||||
w === "¼" && "c-w-1/4",
|
w === "¼" && "c-w-1/4",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const FieldInput: FC<{
|
||||||
_item: any;
|
_item: any;
|
||||||
_meta: any;
|
_meta: any;
|
||||||
_sync: (mitem: any, item: any) => void;
|
_sync: (mitem: any, item: any) => void;
|
||||||
}> = ({ field, fm, PassProp, child, _meta, _item }) => {
|
}> = ({ field, fm, PassProp, child, _meta, _item, _sync }) => {
|
||||||
const prefix = typeof field.prefix === "function" ? field.prefix() : null;
|
const prefix = typeof field.prefix === "function" ? field.prefix() : null;
|
||||||
const suffix = typeof field.suffix === "function" ? field.suffix() : null;
|
const suffix = typeof field.suffix === "function" ? field.suffix() : null;
|
||||||
const errors = fm.error.get(field.name);
|
const errors = fm.error.get(field.name);
|
||||||
|
|
@ -31,26 +31,35 @@ export const FieldInput: FC<{
|
||||||
let found = null as any;
|
let found = null as any;
|
||||||
if (childs && childs.length > 0) {
|
if (childs && childs.length > 0) {
|
||||||
for (const child of childs) {
|
for (const child of childs) {
|
||||||
if (child.component?.id === fieldMapping[field.type].id) {
|
const mp = (fieldMapping as any)[field.type];
|
||||||
|
if (child.component?.id === mp.id) {
|
||||||
found = child;
|
found = child;
|
||||||
|
|
||||||
const item = createItem({
|
if (mp.props) {
|
||||||
component: { id: "--", props: fieldMapping[field.type].props },
|
const item = createItem({
|
||||||
});
|
component: {
|
||||||
|
id: "--",
|
||||||
|
props:
|
||||||
|
typeof mp.props === "function" ? mp.props(fm, field) : mp.props,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const props = found.component.props;
|
const props = found.component.props;
|
||||||
let should_update = false;
|
let should_update = false;
|
||||||
for (const [k, v] of Object.entries(item.component.props) as any) {
|
for (const [k, v] of Object.entries(item.component.props) as any) {
|
||||||
if (props[k] && props[k].valueBuilt === v.valueBuilt) {
|
if (props[k] && props[k].valueBuilt === v.valueBuilt) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
props[k] = v;
|
if (field.prop && !field.prop[k]) {
|
||||||
should_update = true;
|
props[k] = v;
|
||||||
|
should_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (should_update) {
|
if (should_update) {
|
||||||
updateFieldMItem(_meta, found);
|
updateFieldMItem(_meta, found, _sync);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -58,14 +67,14 @@ export const FieldInput: FC<{
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEditor && !found) {
|
if (isEditor && !found) {
|
||||||
genFieldMitem({ _meta, _item, field, fm });
|
genFieldMitem({ _meta, _item, _sync, field, fm });
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
"field-inner c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm",
|
"field-outer c-flex c-flex-1 c-flex-row c-rounded c-border c-text-sm",
|
||||||
fm.status === "loading"
|
fm.status === "loading"
|
||||||
? css`
|
? css`
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,29 @@
|
||||||
import { FieldProp } from "../typings";
|
import { FMLocal, FieldInternal, FieldLocal, FieldProp } from "../typings";
|
||||||
|
|
||||||
export const fieldMapping: Record<
|
export const fieldMapping: {
|
||||||
FieldProp["type"],
|
[K in FieldProp["type"]]: {
|
||||||
{ id: string; props: any }
|
id: string;
|
||||||
> = {
|
props?:
|
||||||
|
| Record<string, any>
|
||||||
|
| ((
|
||||||
|
fm: FMLocal,
|
||||||
|
field: FieldInternal<K> & {
|
||||||
|
render: () => void;
|
||||||
|
}
|
||||||
|
) => Record<string, any>);
|
||||||
|
};
|
||||||
|
} = {
|
||||||
text: { id: "ca7ac237-8f22-4492-bb9d-4b715b1f5c25", props: { type: "text" } },
|
text: { id: "ca7ac237-8f22-4492-bb9d-4b715b1f5c25", props: { type: "text" } },
|
||||||
number: {
|
relation: {
|
||||||
id: "ca7ac237-8f22-4492-bb9d-4b715b1f5c25",
|
id: "69263ca0-61a1-4899-ad5f-059ac12b94d1",
|
||||||
props: { type: "number" },
|
props: (fm, field) => {
|
||||||
|
const rel = fm.field_def[field.name];
|
||||||
|
if (rel) {
|
||||||
|
if (field.prop && !field.prop.type) {
|
||||||
|
return { type: rel.type };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as any;
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
import { Popover } from "@/comps/custom/Popover";
|
||||||
|
import { useLocal } from "@/utils/use-local";
|
||||||
|
import { ChevronDown } from "lucide-react";
|
||||||
|
import { FC, ReactNode } from "react";
|
||||||
|
|
||||||
|
type OptionItem = { value: string; label: string; el?: ReactNode };
|
||||||
|
|
||||||
|
export const RawDropdown: FC<{
|
||||||
|
options: OptionItem[];
|
||||||
|
className?: string;
|
||||||
|
value: string;
|
||||||
|
onFocus?: () => void;
|
||||||
|
onBlur?: () => void;
|
||||||
|
onChange?: (value: string) => void;
|
||||||
|
}> = ({ value, options, className, onFocus, onBlur, onChange }) => {
|
||||||
|
const local = useLocal({
|
||||||
|
open: false,
|
||||||
|
input: {
|
||||||
|
value: "",
|
||||||
|
el: null as any,
|
||||||
|
},
|
||||||
|
filter: "",
|
||||||
|
width: 0,
|
||||||
|
selected: undefined as undefined | OptionItem,
|
||||||
|
});
|
||||||
|
|
||||||
|
let filtered = options;
|
||||||
|
|
||||||
|
if (local.filter) {
|
||||||
|
filtered = options.filter((e) => {
|
||||||
|
if (e.label.toLowerCase().includes(local.filter)) return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
local.selected = options.find((e) => e.value === value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
open={local.open}
|
||||||
|
onOpenChange={() => {
|
||||||
|
local.open = false;
|
||||||
|
local.render();
|
||||||
|
}}
|
||||||
|
arrow={false}
|
||||||
|
className={cx("c-rounded-sm c-bg-white")}
|
||||||
|
content={
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-text-sm",
|
||||||
|
css`
|
||||||
|
width: ${local.width || 100}px;
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{filtered.map((item, idx) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
tabIndex={0}
|
||||||
|
key={item.value + "_" + idx}
|
||||||
|
className={cx(
|
||||||
|
"c-px-3 c-py-1 cursor-pointer option-item",
|
||||||
|
item.value === value
|
||||||
|
? "c-bg-blue-600 c-text-white"
|
||||||
|
: "hover:c-bg-blue-50",
|
||||||
|
idx > 0 && "c-border-t",
|
||||||
|
idx === 0 && "c-rounded-t-sm",
|
||||||
|
idx === filtered.length - 1 && "c-rounded-b-sm"
|
||||||
|
)}
|
||||||
|
onClick={() => {
|
||||||
|
if (onChange) onChange(item.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-relative",
|
||||||
|
className,
|
||||||
|
css`
|
||||||
|
cursor: pointer !important;
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
tabIndex={0}
|
||||||
|
onFocus={() => {
|
||||||
|
local.open = true;
|
||||||
|
if (local.selected) local.input.value = local.selected.label;
|
||||||
|
local.filter = "";
|
||||||
|
local.render();
|
||||||
|
setTimeout(() => {
|
||||||
|
local.input.el?.focus();
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
ref={(el) => {
|
||||||
|
if (local.width === 0 && el) {
|
||||||
|
const box = el.getBoundingClientRect();
|
||||||
|
if (box && box.width) {
|
||||||
|
local.width = box.width;
|
||||||
|
local.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="c-w-full c-h-full c-relative">
|
||||||
|
<input
|
||||||
|
spellCheck={false}
|
||||||
|
value={local.open ? local.input.value : "Halo"}
|
||||||
|
className={cx(
|
||||||
|
"c-absolute c-inset-0 c-w-full c-h-full c-outline-none c-p-0",
|
||||||
|
local.open
|
||||||
|
? "c-cursor-pointer"
|
||||||
|
: "c-pointer-events-none c-invisible"
|
||||||
|
)}
|
||||||
|
onChange={(e) => {
|
||||||
|
local.input.value = e.currentTarget.value;
|
||||||
|
local.filter = local.input.value.toLowerCase();
|
||||||
|
local.render();
|
||||||
|
}}
|
||||||
|
ref={(el) => {
|
||||||
|
local.input.el = el;
|
||||||
|
}}
|
||||||
|
type="text"
|
||||||
|
onFocus={onFocus}
|
||||||
|
onBlur={onBlur}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!local.open && local.selected && (
|
||||||
|
<div className="c-absolute c-inset-0 c-z-10 c-w-full c-h-full c-text-sm c-flex c-items-center">
|
||||||
|
{local.selected.el || local.selected.label}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-absolute c-pointer-events-none c-z-10 c-inset-0 c-left-auto c-flex c-items-center ",
|
||||||
|
"c-bg-white c-justify-center c-w-6 c-mr-1 c-my-2"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ChevronDown size={14} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { useLocal } from "@/utils/use-local";
|
||||||
|
import { FC } from "react";
|
||||||
|
import { FMLocal, FieldLocal } from "../../typings";
|
||||||
|
import { RawDropdown } from "../raw/Dropdown";
|
||||||
|
|
||||||
|
export type PropTypeRelation = {
|
||||||
|
type: "has-one" | "has-many";
|
||||||
|
};
|
||||||
|
export const FieldTypeRelation: FC<{
|
||||||
|
field: FieldLocal;
|
||||||
|
fm: FMLocal;
|
||||||
|
prop: PropTypeRelation;
|
||||||
|
}> = ({ field, fm, prop }) => {
|
||||||
|
const input = useLocal({});
|
||||||
|
const value = fm.data[field.name];
|
||||||
|
field.input = input;
|
||||||
|
field.prop = prop;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RawDropdown
|
||||||
|
options={[{ label: "Halo", value: "halo" }]}
|
||||||
|
value={"halo"}
|
||||||
|
className="c-flex-1 c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full c-h-full"
|
||||||
|
onFocus={() => {
|
||||||
|
field.focused = true;
|
||||||
|
field.render();
|
||||||
|
}}
|
||||||
|
onBlur={() => {
|
||||||
|
field.focused = false;
|
||||||
|
field.render();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,14 +1,21 @@
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { FMLocal, FieldLocal } from "../../typings";
|
import { FMLocal, FieldLocal } from "../../typings";
|
||||||
|
import { useLocal } from "@/utils/use-local";
|
||||||
|
|
||||||
|
export type PropTypeText = {
|
||||||
|
type: "text" | "password" | "number";
|
||||||
|
};
|
||||||
|
|
||||||
export const FieldTypeText: FC<{
|
export const FieldTypeText: FC<{
|
||||||
field: FieldLocal;
|
field: FieldLocal;
|
||||||
fm: FMLocal;
|
fm: FMLocal;
|
||||||
prop: {
|
prop: PropTypeText;
|
||||||
type: "text" | "password" | "number";
|
|
||||||
};
|
|
||||||
}> = ({ field, fm, prop }) => {
|
}> = ({ field, fm, prop }) => {
|
||||||
|
const input = useLocal({});
|
||||||
const value = fm.data[field.name];
|
const value = fm.data[field.name];
|
||||||
|
field.input = input;
|
||||||
|
field.prop = prop;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
type={prop.type}
|
type={prop.type}
|
||||||
|
|
@ -18,7 +25,7 @@ export const FieldTypeText: FC<{
|
||||||
}}
|
}}
|
||||||
value={value || ""}
|
value={value || ""}
|
||||||
disabled={field.disabled}
|
disabled={field.disabled}
|
||||||
className="c-flex-1 c-rounded c-bg-transparent c-outline-none c-px-2 c-text-sm"
|
className="c-flex-1 c-bg-transparent c-outline-none c-px-2 c-text-sm"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
field.focused = true;
|
field.focused = true;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { GFCol } from "@/gen/utils";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { SliderOptions } from "../form-old/Slider/types";
|
|
||||||
import { FieldOptions } from "../form-old/type";
|
import { FieldOptions } from "../form-old/type";
|
||||||
import { FormHook } from "../form-old/utils/utils";
|
import { FormHook } from "../form-old/utils/utils";
|
||||||
import { editorFormData } from "./utils/ed-data";
|
import { editorFormData } from "./utils/ed-data";
|
||||||
|
import { PropTypeText } from "./field/type/TypeText";
|
||||||
|
import { PropTypeRelation } from "./field/type/TypeRelation";
|
||||||
|
|
||||||
export type FMProps = {
|
export type FMProps = {
|
||||||
on_init: (arg: { fm: FMLocal; submit: any; reload: any }) => any;
|
on_init: (arg: { fm: FMLocal; submit: any; reload: any }) => any;
|
||||||
|
|
@ -18,6 +20,7 @@ export type FMProps = {
|
||||||
item: any;
|
item: any;
|
||||||
label_mode: "vertical" | "horizontal" | "hidden";
|
label_mode: "vertical" | "horizontal" | "hidden";
|
||||||
label_width: number;
|
label_width: number;
|
||||||
|
gen_fields: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FieldProp = {
|
export type FieldProp = {
|
||||||
|
|
@ -26,20 +29,18 @@ export type FieldProp = {
|
||||||
desc?: string;
|
desc?: string;
|
||||||
props?: any;
|
props?: any;
|
||||||
fm: FMLocal;
|
fm: FMLocal;
|
||||||
type:
|
type: "text" | "relation";
|
||||||
| "text"
|
// | "number"
|
||||||
| "number"
|
// | "textarea"
|
||||||
| "textarea"
|
// | "dropdown"
|
||||||
| "dropdown"
|
// | "password"
|
||||||
| "relation"
|
// | "radio"
|
||||||
| "password"
|
// | "date"
|
||||||
| "radio"
|
// | "datetime"
|
||||||
| "date"
|
// | "money"
|
||||||
| "datetime"
|
// | "slider"
|
||||||
| "money"
|
// | "master-link"
|
||||||
| "slider"
|
// | "custom";
|
||||||
| "master-link"
|
|
||||||
| "custom";
|
|
||||||
required: "y" | "n";
|
required: "y" | "n";
|
||||||
required_msg: (name: string) => string;
|
required_msg: (name: string) => string;
|
||||||
options: FieldOptions;
|
options: FieldOptions;
|
||||||
|
|
@ -50,7 +51,7 @@ export type FieldProp = {
|
||||||
selection: "single" | "multi";
|
selection: "single" | "multi";
|
||||||
prefix: any;
|
prefix: any;
|
||||||
suffix: any;
|
suffix: any;
|
||||||
width: "auto" | "full" | "½" | "⅓" | "¼";
|
width: "auto" | "full" | "¾" | "½" | "⅓" | "¼";
|
||||||
_meta: any;
|
_meta: any;
|
||||||
_item: any;
|
_item: any;
|
||||||
_sync: any;
|
_sync: any;
|
||||||
|
|
@ -65,6 +66,7 @@ export type FMInternal = {
|
||||||
on_change: (name: string, new_value: any) => void;
|
on_change: (name: string, new_value: any) => void;
|
||||||
};
|
};
|
||||||
fields: Record<string, FieldLocal>;
|
fields: Record<string, FieldLocal>;
|
||||||
|
field_def: Record<string, GFCol>;
|
||||||
error: {
|
error: {
|
||||||
readonly list: { name: string; error: string[] }[];
|
readonly list: { name: string; error: string[] }[];
|
||||||
set: (name: string, error: string[]) => void;
|
set: (name: string, error: string[]) => void;
|
||||||
|
|
@ -87,10 +89,16 @@ export type FMInternal = {
|
||||||
};
|
};
|
||||||
export type FMLocal = FMInternal & { render: () => void };
|
export type FMLocal = FMInternal & { render: () => void };
|
||||||
|
|
||||||
export type FieldInternal = {
|
type FieldInternalProp = {
|
||||||
|
text: PropTypeText;
|
||||||
|
number: PropTypeText;
|
||||||
|
relation: PropTypeRelation;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FieldInternal<T extends FieldProp["type"]> = {
|
||||||
status: "init" | "loading" | "ready";
|
status: "init" | "loading" | "ready";
|
||||||
name: FieldProp["name"];
|
name: FieldProp["name"];
|
||||||
type: FieldProp["type"];
|
type: T;
|
||||||
label: FieldProp["label"];
|
label: FieldProp["label"];
|
||||||
desc: FieldProp["desc"];
|
desc: FieldProp["desc"];
|
||||||
prefix: FieldProp["prefix"];
|
prefix: FieldProp["prefix"];
|
||||||
|
|
@ -100,9 +108,16 @@ export type FieldInternal = {
|
||||||
focused: boolean;
|
focused: boolean;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
required_msg: FieldProp["required_msg"];
|
required_msg: FieldProp["required_msg"];
|
||||||
|
col?: GFCol;
|
||||||
Child: () => ReactNode;
|
Child: () => ReactNode;
|
||||||
|
input: Record<string, any> & {
|
||||||
|
render: () => void;
|
||||||
|
};
|
||||||
|
prop?: FieldInternalProp[T];
|
||||||
|
};
|
||||||
|
export type FieldLocal = FieldInternal<any> & {
|
||||||
|
render: () => void;
|
||||||
};
|
};
|
||||||
export type FieldLocal = FieldInternal & { render: () => void };
|
|
||||||
|
|
||||||
export const formType = (active: { item_id: string }, meta: any) => {
|
export const formType = (active: { item_id: string }, meta: any) => {
|
||||||
let data = "null as any";
|
let data = "null as any";
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
|
import { newField } from "@/gen/gen_form/new_field";
|
||||||
import { FMLocal, FieldLocal } from "../typings";
|
import { FMLocal, FieldLocal } from "../typings";
|
||||||
|
import get from "lodash.get";
|
||||||
|
import { fieldMapping } from "../field/mapping";
|
||||||
|
import { createItem } from "@/gen/utils";
|
||||||
|
|
||||||
export const genFieldMitem = (arg: {
|
export const genFieldMitem = (arg: {
|
||||||
_meta: any;
|
_meta: any;
|
||||||
_item: any;
|
_item: any;
|
||||||
|
_sync: any;
|
||||||
fm: FMLocal;
|
fm: FMLocal;
|
||||||
field: FieldLocal;
|
field: FieldLocal;
|
||||||
}) => {
|
}) => {
|
||||||
const { _meta, _item, fm, field } = arg;
|
const { _meta, _item, _sync, fm, field } = arg;
|
||||||
const m = _meta[_item.id];
|
const m = _meta[_item.id];
|
||||||
if (m) {
|
if (m) {
|
||||||
const mitem = m.mitem;
|
const mitem = m.mitem;
|
||||||
|
|
@ -18,16 +23,27 @@ export const genFieldMitem = (arg: {
|
||||||
?.get("content")
|
?.get("content")
|
||||||
?.get("childs");
|
?.get("childs");
|
||||||
|
|
||||||
// console.log(field.name, childs);
|
const col = fm.field_def[field.name];
|
||||||
|
if (col) {
|
||||||
|
const component = fieldMapping[field.type as "text"];
|
||||||
|
if (component) {
|
||||||
|
const item = createItem({
|
||||||
|
component: component as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
_sync(childs, [...childs.toJSON(), item]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const updateFieldMItem = (_meta: any, _item: any) => {
|
|
||||||
|
export const updateFieldMItem = (_meta: any, _item: any, _sync: any) => {
|
||||||
const m = _meta[_item.id];
|
const m = _meta[_item.id];
|
||||||
if (m) {
|
if (m) {
|
||||||
const mitem = m.mitem;
|
const mitem = m.mitem;
|
||||||
if (mitem) {
|
if (mitem) {
|
||||||
|
_sync(mitem, _item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
import { parseGenField } from "@/gen/utils";
|
||||||
|
import get from "lodash.get";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { FMLocal, FMProps } from "../typings";
|
import { FMLocal, FMProps } from "../typings";
|
||||||
import { formError } from "./error";
|
|
||||||
import { editorFormData } from "./ed-data";
|
import { editorFormData } from "./ed-data";
|
||||||
import get from "lodash.get";
|
import { formError } from "./error";
|
||||||
|
|
||||||
export const formInit = (fm: FMLocal, props: FMProps) => {
|
export const formInit = (fm: FMLocal, props: FMProps) => {
|
||||||
for (const [k, v] of Object.entries(props)) {
|
for (const [k, v] of Object.entries(props)) {
|
||||||
|
|
@ -13,6 +14,14 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
||||||
const { on_load, sonar } = fm.props;
|
const { on_load, sonar } = fm.props;
|
||||||
fm.error = formError(fm);
|
fm.error = formError(fm);
|
||||||
|
|
||||||
|
if (isEditor) {
|
||||||
|
fm.field_def = {};
|
||||||
|
const defs = parseGenField(fm.props.gen_fields);
|
||||||
|
for (const d of defs) {
|
||||||
|
fm.field_def[d.name] = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fm.reload = () => {
|
fm.reload = () => {
|
||||||
fm.status = isEditor ? "ready" : "loading";
|
fm.status = isEditor ? "ready" : "loading";
|
||||||
fm.render();
|
fm.render();
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@ import { FMLocal, FieldInternal, FieldProp } from "../typings";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export const useField = (arg: FieldProp) => {
|
export const useField = (arg: FieldProp) => {
|
||||||
const field = useLocal<FieldInternal>({
|
const field = useLocal<FieldInternal<typeof arg.type>>({
|
||||||
status: "init",
|
status: "init",
|
||||||
Child: () => {
|
Child: () => {
|
||||||
return <arg.PassProp>{arg.child}</arg.PassProp>;
|
return <arg.PassProp>{arg.child}</arg.PassProp>;
|
||||||
},
|
},
|
||||||
|
input: {},
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
const update_field = {
|
const update_field = {
|
||||||
|
|
|
||||||
1
data.ts
1
data.ts
|
|
@ -1,4 +1,5 @@
|
||||||
export { FieldTypeText } from "./comps/form/field/type/TypeText";
|
export { FieldTypeText } from "./comps/form/field/type/TypeText";
|
||||||
|
export { FieldTypeRelation } from "./comps/form/field/type/TypeRelation";
|
||||||
export { Form } from "@/comps/form/Form";
|
export { Form } from "@/comps/form/Form";
|
||||||
export { Field } from "@/comps/form/field/Field";
|
export { Field } from "@/comps/form/field/Field";
|
||||||
export { formType } from "@/comps/form/typings";
|
export { formType } from "@/comps/form/typings";
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import get from "lodash.get";
|
import { codeBuild } from "../master_detail/utils";
|
||||||
import { GFCol as Col, GFCol, formatName, parseGenField } from "../utils";
|
import { GFCol, parseGenField } from "../utils";
|
||||||
import { NewFieldArg, newField } from "./new_field";
|
import { newField } from "./new_field";
|
||||||
import { on_load } from "./on_load";
|
import { on_load } from "./on_load";
|
||||||
import { on_submit } from "./on_submit";
|
import { on_submit } from "./on_submit";
|
||||||
import { codeBuild } from "../master_detail/utils";
|
|
||||||
|
|
||||||
export const gen_form = async (modify: (data: any) => void, data: any) => {
|
export const gen_form = async (modify: (data: any) => void, data: any) => {
|
||||||
const table = JSON.parse(data.gen_table.value);
|
const table = JSON.parse(data.gen_table.value);
|
||||||
|
|
@ -57,7 +56,7 @@ export const gen_form = async (modify: (data: any) => void, data: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
result["body"] = data["body"];
|
result["body"] = data["body"];
|
||||||
result.body.content.childs = fields.map(newField);
|
result.body.content.childs = fields.filter((e) => !e.is_pk).map(newField);
|
||||||
}
|
}
|
||||||
modify(result);
|
modify(result);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,23 +29,43 @@ export type NewFieldArg = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newField = (arg: GFCol) => {
|
export const newField = (arg: GFCol) => {
|
||||||
|
const childs = [];
|
||||||
|
|
||||||
|
let type = "text";
|
||||||
|
if (["int", "string"].includes(arg.type)) {
|
||||||
|
childs.push(
|
||||||
|
createItem({
|
||||||
|
component: {
|
||||||
|
id: "ca7ac237-8f22-4492-bb9d-4b715b1f5c25",
|
||||||
|
props: {
|
||||||
|
type: arg.type === "int" ? "number" : "text",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if (["has-many", "has-one"].includes(arg.type)) {
|
||||||
|
type = "relation";
|
||||||
|
childs.push(
|
||||||
|
createItem({
|
||||||
|
component: {
|
||||||
|
id: "69263ca0-61a1-4899-ad5f-059ac12b94d1",
|
||||||
|
props: {
|
||||||
|
type: arg.type,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const item = createItem({
|
const item = createItem({
|
||||||
component: {
|
component: {
|
||||||
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
id: "32550d01-42a3-4b15-a04a-2c2d5c3c8e67",
|
||||||
props: {
|
props: {
|
||||||
name: arg.name,
|
name: arg.name,
|
||||||
label: formatName(arg.name),
|
label: formatName(arg.name),
|
||||||
|
type,
|
||||||
child: {
|
child: {
|
||||||
childs: [
|
childs,
|
||||||
createItem({
|
|
||||||
component: {
|
|
||||||
id: "ca7ac237-8f22-4492-bb9d-4b715b1f5c25",
|
|
||||||
props: {
|
|
||||||
type: "text",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue