This commit is contained in:
rizky 2024-11-22 06:26:59 -07:00
parent f458d4e46c
commit 8425b4ea95
5 changed files with 163 additions and 46 deletions

View File

@ -10,7 +10,7 @@ import { getPathname } from "lib/utils/pathname";
import { sofDeleteField as softDeleteField } from "lib/utils/soft-del-rel"; import { sofDeleteField as softDeleteField } from "lib/utils/soft-del-rel";
import { toast } from "../ui/toast"; import { toast } from "../ui/toast";
const editorFormWidth = {} as Record<string, { w: number; f: any }>; export const editorFormWidth = {} as Record<string, { w: number; f: any }>;
export type { FMLocal } from "./typings"; export type { FMLocal } from "./typings";

View File

@ -19,18 +19,32 @@ export const BaseField = (prop: {
typeof field.prefix === "function" typeof field.prefix === "function"
? field.prefix() ? field.prefix()
: typeof field.prefix === "string" : typeof field.prefix === "string"
? field.prefix ? field.prefix
: null; : null;
const suffix = const suffix =
typeof field.suffix === "function" typeof field.suffix === "function"
? field.suffix() ? field.suffix()
: typeof field.suffix === "string" : typeof field.suffix === "string"
? field.prefix ? field.prefix
: 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 =
typeof field.disabled === "function" ? field.disabled() : field.disabled;
const show =
typeof field.hidden === "function"
? field.hidden()
: typeof field.hidden === "string"
? field.hidden === "n"
? false
: true
: typeof field.hidden === "boolean"
? field.hidden
: true;
return ( return (
<label <label
className={cx( className={cx(
@ -48,6 +62,16 @@ export const BaseField = (prop: {
w === "⅓" && "c-w-1/3", w === "⅓" && "c-w-1/3",
w === "¼" && "c-w-1/4", w === "¼" && "c-w-1/4",
"c-flex-col c-space-y-1", "c-flex-col c-space-y-1",
css`
.field-outer {
border: 1px solid ${disabled ? "#ececeb" : "#cecece"};
&.focused {
border: 1px solid #1c4ed8;
outline: 1px solid #1c4ed8;
}
}
`,
field.focused && "focused", field.focused && "focused",
field.disabled && "disabled", field.disabled && "disabled",
typeof fm.data[name] !== "undefined" && typeof fm.data[name] !== "undefined" &&
@ -56,8 +80,19 @@ export const BaseField = (prop: {
"filled" "filled"
)} )}
> >
{arg.show_label !== "n" && <Label field={field} fm={fm} arg={arg}/>} {arg.show_label !== "n" && <Label field={field} fm={fm} arg={arg} />}
<div className="field-input c-flex c-flex-1 c-flex-col"> <div
className={cx(
"field-input c-flex c-flex-1 c-flex-col",
errors.length > 0 &&
css`
.field-outer {
border-color: red !important;
background: #fff0f0;
}
`
)}
>
<div <div
className={cx( className={cx(
!["toggle", "button", "radio", "checkbox"].includes(arg.sub_type) !["toggle", "button", "radio", "checkbox"].includes(arg.sub_type)
@ -71,12 +106,12 @@ export const BaseField = (prop: {
border-color: transparent; border-color: transparent;
` `
: field.disabled : field.disabled
? "c-border-gray-100" ? "c-border-gray-100"
: errors.length > 0 : errors.length > 0
? field.focused ? field.focused
? "c-border-red-600 c-bg-red-50 c-outline c-outline-red-700" ? "c-border-red-600 c-bg-red-50 c-outline c-outline-red-700"
: "c-border-red-600 c-bg-red-50" : "c-border-red-600 c-bg-red-50"
: field.focused && "focused", : field.focused && "focused",
css` css`
& > .field-inner { & > .field-inner {
min-height: 35px; min-height: 35px;

View File

@ -1,8 +1,10 @@
import { useLocal } from "lib/utils/use-local"; import { useLocal } from "lib/utils/use-local";
import { ReactNode, useCallback, useEffect } from "react"; import { ReactNode, useCallback, useEffect, useRef } from "react";
import { FieldLocal, FieldProp, FMLocal } from "../typings"; import { FieldLocal, FieldProp, FMLocal } from "../typings";
import { BaseFormLocal, default_base_form_local } from "./types"; import { BaseFormLocal, default_base_form_local } from "./types";
import { FieldLoading } from "lib/comps/ui/field-loading"; import { FieldLoading } from "lib/comps/ui/field-loading";
import { editorFormWidth } from "../Form";
import { ConsoleLogWriter } from "drizzle-orm";
export type BaseFormProps<T> = { export type BaseFormProps<T> = {
data: T; data: T;
@ -12,6 +14,7 @@ export type BaseFormProps<T> = {
render?: () => void; render?: () => void;
on_change?: (fm: FMLocal, name: string, new_value: any) => any; on_change?: (fm: FMLocal, name: string, new_value: any) => any;
is_form?: boolean; is_form?: boolean;
name: string;
}; };
export const BaseForm = <T extends Record<string, any>>( export const BaseForm = <T extends Record<string, any>>(
props: BaseFormProps<T> props: BaseFormProps<T>
@ -107,10 +110,58 @@ export const BaseForm = <T extends Record<string, any>>(
}; };
}; };
useEffect(() => { const ref = useRef({
// form.data = data; el: null as null | HTMLFormElement,
// form.render(); 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<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 (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) { if (form.internal.width === 0) {
setTimeout(() => { setTimeout(() => {
form.render(); form.render();
@ -125,6 +176,7 @@ export const BaseForm = <T extends Record<string, any>>(
if (!form.fm) { if (!form.fm) {
form.fm = form.createFm(); form.fm = form.createFm();
} }
const fm = form.fm;
if (typeof props.is_form === "boolean") { if (typeof props.is_form === "boolean") {
if (!props.is_form) { if (!props.is_form) {
@ -149,29 +201,45 @@ export const BaseForm = <T extends Record<string, any>>(
e.stopPropagation(); e.stopPropagation();
form.submit(); 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( className={cx(
"form c-flex-1 c-flex c-flex-col c-w-full c-h-full c-relative c-overflow-auto", "form c-flex-1 c-flex c-flex-col c-w-full c-h-full c-relative c-overflow-auto",
className className
)} )}
> >
<div {fm?.status === "ready" && (
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", <div
css` className={cx(
padding-right: 10px; "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; ref={(el) => {
form.createFm(); if (el?.offsetWidth) {
} form.internal.width = el?.offsetWidth;
}} form.createFm();
> }
{form.internal.width > 0 && ( }}
<>{typeof children === "function" ? children(form) : children}</> >
)} {form.internal.width > 0 && (
</div> <>{typeof children === "function" ? children(form) : children}</>
)}
</div>
</>
)}
</form> </form>
); );
}; };

View File

@ -104,14 +104,16 @@ export const Field: FC<FieldProp> = (arg) => {
const disabled = const disabled =
typeof field.disabled === "function" ? field.disabled() : field.disabled; typeof field.disabled === "function" ? field.disabled() : field.disabled;
const show = const show =
typeof field.hidden === "function" typeof field.hidden === "function"
? field.hidden() ? field.hidden()
: typeof field.hidden === "string" : typeof field.hidden === "string"
? field.hidden === "n" ? field.hidden === "n"
? false ? false
: true : true
: typeof field.hidden === "boolean"? field.hidden : true; : typeof field.hidden === "boolean"
? field.hidden
: true;
if (!show) return <></>; if (!show) return <></>;
return ( return (
@ -153,8 +155,21 @@ export const Field: FC<FieldProp> = (arg) => {
)} )}
ref={typeof arg.field_ref === "function" ? arg.field_ref : undefined} ref={typeof arg.field_ref === "function" ? arg.field_ref : undefined}
> >
{showlabel !== "n" && field.label && <Label field={field} fm={fm} arg={arg}/>} {showlabel !== "n" && field.label && (
<div className={cx("field-input c-flex c-flex-1 c-flex-col")}> <Label field={field} fm={fm} arg={arg} />
)}
<div
className={cx(
"field-input c-flex c-flex-1 c-flex-col",
errors.length > 0 &&
css`
.field-outer {
border-color: red !important;
background: #fff0f0;
}
`
)}
>
<FieldInput <FieldInput
field={field} field={field}
fm={fm} fm={fm}

View File

@ -1,8 +1,9 @@
import { GFCol, parseGenField } from "lib/gen/utils"; import { GFCol, parseGenField } from "lib/gen/utils";
import { cn } from "lib/utils"; import { cn } from "lib/utils";
import { fields_map } from "lib/utils/format-value"; import { fields_map } from "lib/utils/format-value";
import { useLocal } from "lib/utils/use-local"; import { call_prasi_events } from "lib/utils/prasi-events";
import { set } from "lib/utils/set"; import { set } from "lib/utils/set";
import { useLocal } from "lib/utils/use-local";
import get from "lodash.get"; import get from "lodash.get";
import { import {
AlertTriangle, AlertTriangle,
@ -23,8 +24,7 @@ import DataGrid, {
ColumnOrColumnGroup, ColumnOrColumnGroup,
RenderCellProps, RenderCellProps,
Row, Row,
SELECT_COLUMN_KEY, SortColumn
SortColumn,
} from "react-data-grid"; } from "react-data-grid";
import "react-data-grid/lib/styles.css"; import "react-data-grid/lib/styles.css";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
@ -38,7 +38,6 @@ import { TLList } from "./TLList";
import { TLSlider } from "./TLSlider"; import { TLSlider } from "./TLSlider";
import { sortTree } from "./utils/sort-tree"; import { sortTree } from "./utils/sort-tree";
import { OnRowClick } from "./utils/type"; import { OnRowClick } from "./utils/type";
import { call_prasi_events } from "lib/utils/prasi-events";
let EMPTY_SET = new Set() as ReadonlySet<any>; let EMPTY_SET = new Set() as ReadonlySet<any>;