From e096b9dd34570a6a494fe6049e627c4022a7e037 Mon Sep 17 00:00:00 2001 From: rizrmd Date: Sun, 19 May 2024 02:47:23 -0700 Subject: [PATCH] fix master detail --- comps/custom/Breadcrumb.tsx | 87 ++-- comps/form/base/BaseField.tsx | 58 --- comps/form/base/BaseForm.tsx | 51 --- comps/form/base/BaseLabel.tsx | 49 --- comps/form/base/utils/init.ts | 35 -- comps/form/base/utils/reload.ts | 7 - comps/form/base/utils/submit.ts | 9 - comps/form/base/utils/type/field.ts | 57 --- comps/form/base/utils/type/form.ts | 8 - comps/form/base/utils/use-field.ts | 28 -- comps/form/field/Field.tsx | 5 +- comps/form/field/FieldInput.tsx | 23 +- comps/form/field/mapping.ts | 30 -- comps/form/field/plugin/ToolbarPlugin.tsx | 172 -------- comps/form/field/plugin/TreeViewPlugin.tsx | 25 -- comps/form/field/plugin/richtext.css | 451 --------------------- comps/form/field/type/TypeCheckbox.tsx | 5 +- comps/form/field/type/TypeMoney.tsx | 6 +- comps/form/field/type/TypeRelation.tsx | 6 +- comps/form/field/type/TypeRichText.tsx | 11 +- comps/form/field/type/TypeSwitch.tsx | 16 +- comps/form/field/type/TypeTag.tsx | 5 +- comps/form/field/type/TypeUpload.tsx | 7 +- comps/form/typings.ts | 10 +- comps/form/utils/gen-mitem.ts | 50 --- comps/form/utils/use-field.tsx | 5 +- comps/md/MDAction.tsx | 2 +- comps/md/MasterDetail.tsx | 171 ++++---- comps/md/utils/typings.ts | 4 + comps/ui/form.tsx | 177 -------- data.ts | 4 +- gen/prop/gen_prop_fields.ts | 2 + gen/prop/gen_prop_table.ts | 2 + 33 files changed, 159 insertions(+), 1419 deletions(-) delete mode 100755 comps/form/base/BaseField.tsx delete mode 100755 comps/form/base/BaseForm.tsx delete mode 100755 comps/form/base/BaseLabel.tsx delete mode 100755 comps/form/base/utils/init.ts delete mode 100755 comps/form/base/utils/reload.ts delete mode 100755 comps/form/base/utils/submit.ts delete mode 100755 comps/form/base/utils/type/field.ts delete mode 100755 comps/form/base/utils/type/form.ts delete mode 100755 comps/form/base/utils/use-field.ts delete mode 100755 comps/form/field/mapping.ts delete mode 100755 comps/form/field/plugin/ToolbarPlugin.tsx delete mode 100755 comps/form/field/plugin/TreeViewPlugin.tsx delete mode 100755 comps/form/field/plugin/richtext.css delete mode 100755 comps/form/utils/gen-mitem.ts delete mode 100755 comps/ui/form.tsx diff --git a/comps/custom/Breadcrumb.tsx b/comps/custom/Breadcrumb.tsx index 1ea8e17..f7c7767 100755 --- a/comps/custom/Breadcrumb.tsx +++ b/comps/custom/Breadcrumb.tsx @@ -1,5 +1,5 @@ import { useLocal } from "@/utils/use-local"; -import { FC, ReactNode } from "react"; +import { FC, ReactNode, useEffect } from "react"; import { Skeleton } from "../ui/skeleton"; export type BreadItem = { @@ -8,85 +8,55 @@ export type BreadItem = { onClick?: (ev: any) => void; }; -const breadcrumbData = {} as Record; - type BreadcrumbProps = { on_load?: () => Promise; className?: string; - props?: any; value?: BreadItem[]; - item?: any + item?: PrasiItem; }; -export const Breadcrumb: FC = (_arg) => { - const { on_load, item } = _arg; +export const Breadcrumb: FC = ({ + value, + className, + on_load, + item, +}) => { const local = useLocal({ - list: _arg.value || ([] as BreadItem[]), + list: [] as BreadItem[], status: "init" as "init" | "loading" | "ready", params: {}, }); - // code review: md.breadcrumb yang di set di props value dipindahkan di on_load - // dan ketika panjang _arg.value bernilai null maka status berubah menjadi init - // untuk menjalankan on_load - // case: ketika refreshBread dijalankan pada MasterDetail - // md.breadcrum yang awalnya array kosong akan berisi satu array namun - // md.breadcrumb yang diterima di komponen ini tidak berubah tetap seperti - // value default yakni array kosong - if (_arg.value) { - local.list = _arg.value; - local.status = "ready"; - if(!_arg.value.length) local.status = "init" - } - if (local.status === "init") { - let should_load = true; - local.status = "loading"; - if (isEditor && item && breadcrumbData[item.id]) { - local.list = breadcrumbData[item.id]; - local.status = "ready"; - should_load = false; - if(!local.list.length) should_load = true; - } - if (should_load && typeof on_load === "function") { - const callback = (res: any) => { - local.list = res; - if (item) breadcrumbData[item.id] = res; - local.status = "ready"; - }; - const res = on_load(); - if (res instanceof Promise) { - res.then((res) => { - callback(res); - local.render(); - }); - } else callback(res); - } - } - if (isEditor && local.status !== "ready") { - if (item && breadcrumbData[item.id]) { - local.list = breadcrumbData[_arg.item.id]; + useEffect(() => { + if (value) { + local.list = value; + local.status = "ready"; } - local.status = "ready"; - } + + if (typeof on_load === "function") { + local.status = "loading"; + on_load().then((list) => { + local.list = list; + local.status = "ready"; + local.render(); + }); + } + + local.render(); + }, []); return (
{local.status !== "ready" ? ( ) : ( <> - {local.list === null ? ( - <> -

- Null Breadcrumb -

- - ) : ( + {local.list && (local.list || []).map((item, index): ReactNode => { const lastIndex = local.list.length - 1; @@ -128,8 +98,7 @@ export const Breadcrumb: FC = (_arg) => { )} ); - }) - )} + })} )}
diff --git a/comps/form/base/BaseField.tsx b/comps/form/base/BaseField.tsx deleted file mode 100755 index 8ba7071..0000000 --- a/comps/form/base/BaseField.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { FMLocal } from "../typings"; -import { BaseLabel } from "./BaseLabel"; -import { BaseFieldProps } from "./utils/type/field"; -import { useField } from "./utils/use-field"; - -export const BaseField = >( - arg: BaseFieldProps & { fm: FMLocal } -) => { - const field = useField(arg); - const fm = arg.fm; - const mode = fm.props.label_mode || "vertical"; - const props = arg.props; - const w = field.width; - const errors = fm.error.get(field.name); - - return ( - - ); -}; diff --git a/comps/form/base/BaseForm.tsx b/comps/form/base/BaseForm.tsx deleted file mode 100755 index 086a15d..0000000 --- a/comps/form/base/BaseForm.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useLocal } from "@/utils/use-local"; -import { FC } from "react"; -import { BaseField } from "./BaseField"; -import { initSimpleForm as initBaseForm } from "./utils/init"; -import { BaseFieldProps, BaseFormProps } from "./utils/type/field"; - -type Children> = Exclude< - BaseFormProps["children"], - undefined ->; - -export const BaseForm = >( - arg: BaseFormProps -) => { - const fm = useLocal({ status: "init" } as any); - const local = useLocal({ - Field: null as null | FC>, - children: null as unknown as Children, - }); - - if (fm.status === "init") { - local.Field = (props) => { - return ; - }; - if (arg.children) local.children = arg.children; - else { - local.children = ({ Field }) => { - const data = Object.entries(fm.data); - return ( - <> - {data.map(([key, value]) => { - return ; - })} - - ); - }; - } - initBaseForm(fm, arg); - } - - return ( -
{ - e.preventDefault(); - fm.submit(); - }} - > - {local.Field && local.children({ Field: local.Field })} -
- ); -}; diff --git a/comps/form/base/BaseLabel.tsx b/comps/form/base/BaseLabel.tsx deleted file mode 100755 index d31cfa7..0000000 --- a/comps/form/base/BaseLabel.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { FC } from "react"; -import { BaseFieldLocal } from "./utils/type/field"; -import { FMLocal } from "../typings"; - -export const BaseLabel = >({ - field, - fm, -}: { - field: BaseFieldLocal; - fm: FMLocal; -}) => { - const errors = fm.error.get(field.name); - - return ( -
- 0 && `c-text-red-600`)}> - {field.label} - - {field.required && ( - - - - - - - - )} -
- ); -}; diff --git a/comps/form/base/utils/init.ts b/comps/form/base/utils/init.ts deleted file mode 100755 index 240eac7..0000000 --- a/comps/form/base/utils/init.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { FMLocal } from "../../typings"; -import { formError } from "../../utils/error"; -import { reloadBaseForm } from "./reload"; -import { submitBaseForm } from "./submit"; -import { BaseFormProps } from "./type/field"; - -export const initSimpleForm = >( - fm: FMLocal, - arg: BaseFormProps -) => { - fm.data = {}; - fm.error = formError(fm); - fm.events = { - on_change(name, new_value) {}, - }; - fm.field_def = {}; - fm.fields = {}; - fm.internal = { - submit: { done: [], promises: [], timeout: null as any }, - reload: { done: [], promises: [], timeout: null as any }, - }; - fm.props = {} as any; - fm.reload = async () => { - await reloadBaseForm(fm, arg); - }; - fm.size = { - width: 0, - height: 0, - field: "full", - }; - fm.submit = () => { - return submitBaseForm(fm, arg); - }; - fm.status = "ready"; -}; diff --git a/comps/form/base/utils/reload.ts b/comps/form/base/utils/reload.ts deleted file mode 100755 index 636d5e0..0000000 --- a/comps/form/base/utils/reload.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { FMLocal } from "../../typings"; -import { BaseFormProps } from "./type/field"; - -export const reloadBaseForm = async >( - fm: FMLocal, - arg: BaseFormProps -) => {}; diff --git a/comps/form/base/utils/submit.ts b/comps/form/base/utils/submit.ts deleted file mode 100755 index e6bb2a4..0000000 --- a/comps/form/base/utils/submit.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { FMLocal } from "../../typings"; -import { BaseFormProps } from "./type/field"; - -export const submitBaseForm = async >( - fm: FMLocal, - arg: BaseFormProps -) => { - return true; -}; diff --git a/comps/form/base/utils/type/field.ts b/comps/form/base/utils/type/field.ts deleted file mode 100755 index e13b22f..0000000 --- a/comps/form/base/utils/type/field.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { FC, ReactNode } from "react"; - - -export type BaseFieldWidth = - | "auto" - | "full" - | "¾" - | "½" - | "⅓" - | "¼" - | "1/2" - | "1/3" - | "1/4" - | "3/4"; - -export type BaseFieldType = "text" | "relation"; -export type BaseFieldProps> = { - name: keyof T; - label?: string; - type?: BaseFieldType; - props?: any; - desc?: string; - on_change?: (arg: { value: any }) => void | Promise; - - prefix?: any; - suffix?: any; - - required?: boolean; - required_msg?: (name: string) => string; - disabled?: boolean; - - width?: BaseFieldWidth; -}; - -export type BaseFieldInternal> = { - name: keyof T; - label: ReactNode; - type: BaseFieldType; - desc: string; - on_change: (arg: { value: any }) => void | Promise; - - prefix: any; - suffix: any; - - required: boolean; - required_msg: (name: string) => string; - disabled: boolean; - - width: BaseFieldWidth; - status: "init" | "loading" | "ready"; - - PassProp: any; - child: any; -}; - -export type BaseFieldLocal> = - BaseFieldInternal; diff --git a/comps/form/base/utils/type/form.ts b/comps/form/base/utils/type/form.ts deleted file mode 100755 index 8ff5eab..0000000 --- a/comps/form/base/utils/type/form.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { FC, ReactNode } from "react"; -import { BaseFieldProps } from "./field"; - -export type BaseFormProps> = { - onLoad: () => Promise; - onSubmit: (arg: { data: T | null }) => Promise; - children?: (arg: { Field: FC> }) => ReactNode; -}; diff --git a/comps/form/base/utils/use-field.ts b/comps/form/base/utils/use-field.ts deleted file mode 100755 index e06adf6..0000000 --- a/comps/form/base/utils/use-field.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useLocal } from "@/utils/use-local"; -import { FMLocal } from "../../typings"; -import { - BaseFieldInternal, - BaseFieldLocal, - BaseFieldProps, -} from "./type/field"; -import { formatName } from "@/gen/utils"; - -export const useField = >( - arg: BaseFieldProps & { fm: FMLocal } -) => { - const fm = arg.fm; - const local = useLocal>({ - status: "init", - } as any) as BaseFieldLocal; - - if (local.status === "init") { - local.name = arg.name; - local.label = arg.label || formatName(arg.name as string); - local.type = arg.type || "text"; - local.desc = arg.desc || ""; - local.status = "ready"; - local.width = arg.width || fm.size.field === "full" ? "full" : "1/2"; - } - - return local as BaseFieldLocal; -}; diff --git a/comps/form/field/Field.tsx b/comps/form/field/Field.tsx index dd53710..3b479bd 100755 --- a/comps/form/field/Field.tsx +++ b/comps/form/field/Field.tsx @@ -7,10 +7,9 @@ import { Label } from "./Label"; import { useLocal } from "@/utils/use-local"; export const Field: FC = (arg) => { - console.log({arg}) const { fm } = arg; const field = useField(arg); - const name = typeof field.name === 'function' ? field.name() : field.name; + const name = field.name; const local = useLocal({ prev_val: fm.data[name] }); const mode = fm.props.label_mode; @@ -56,9 +55,7 @@ export const Field: FC = (arg) => { fm={fm} PassProp={arg.PassProp} child={arg.child} - _meta={arg._meta} _item={arg._item} - _sync={arg._sync} arg={arg} /> {field.desc && ( diff --git a/comps/form/field/FieldInput.tsx b/comps/form/field/FieldInput.tsx index 2d0431c..10e0a19 100755 --- a/comps/form/field/FieldInput.tsx +++ b/comps/form/field/FieldInput.tsx @@ -1,16 +1,9 @@ -import { createItem } from "@/gen/utils"; -import get from "lodash.get"; -import { FC, isValidElement, useEffect } from "react"; -import { FMLocal, FieldLocal, FieldProp, FieldTypeCustom } from "../typings"; -import { genFieldMitem, updateFieldMItem } from "../utils/gen-mitem"; -import { fieldMapping } from "./mapping"; +import { FC, isValidElement } from "react"; +import { FMLocal, FieldLocal, FieldProp } from "../typings"; import { FieldLoading } from "./raw/FieldLoading"; -import { TypeCustom } from "./type/TypeCustom"; -import { FieldTypeText, PropTypeText } from "./type/TypeText"; -import { TypeDropdown } from "./type/TypeDropdown"; -import { FieldToggle } from "./type/TypeToggle"; -import { SingleOption } from "./type/TypeSingleOption"; import { MultiOption } from "./type/TypeMultiOption"; +import { SingleOption } from "./type/TypeSingleOption"; +import { FieldTypeText, PropTypeText } from "./type/TypeText"; const modify = { timeout: null as any, @@ -21,15 +14,13 @@ export const FieldInput: FC<{ fm: FMLocal; PassProp: any; child: any; - _item: any; - _meta: any; - _sync: (mitem: any, item: any) => void; + _item: PrasiItem; arg: FieldProp; -}> = ({ field, fm, PassProp, child, _meta, _item, _sync, arg }) => { +}> = ({ field, fm, arg }) => { // return <> const prefix = typeof field.prefix === "function" ? field.prefix() : typeof field.prefix === "string" ? field.prefix : null; const suffix = typeof field.suffix === "function" ? field.suffix() : typeof field.suffix === "string" ? field.prefix : null; - const name = typeof field.name === 'function' ? field.name() : field.name; + const name = field.name; const errors = fm.error.get(name); let type_field = typeof arg.type === 'function' ? arg.type() : arg.type; // tipe field diff --git a/comps/form/field/mapping.ts b/comps/form/field/mapping.ts deleted file mode 100755 index eab3a92..0000000 --- a/comps/form/field/mapping.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { FMLocal, FieldInternal, FieldLocal, FieldProp } from "../typings"; - -export const fieldMapping: { - [K in FieldProp["type"]]: { - id: string; - props?: - | Record - | (( - fm: FMLocal, - field: FieldInternal & { - render: () => void; - } - ) => Record); - }; -} = { - text: { id: "ca7ac237-8f22-4492-bb9d-4b715b1f5c25", props: { type: "text" } }, - relation: { - id: "69263ca0-61a1-4899-ad5f-059ac12b94d1", - props: (fm, field) => { - const rel = fm.field_def[field.name]; - if (rel) { - if (field.prop && !field.prop.type) { - return { type: rel.type }; - } - } - return {}; - }, - }, - switch: { id: ""}, -}; diff --git a/comps/form/field/plugin/ToolbarPlugin.tsx b/comps/form/field/plugin/ToolbarPlugin.tsx deleted file mode 100755 index fcbb96b..0000000 --- a/comps/form/field/plugin/ToolbarPlugin.tsx +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ -import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import {mergeRegister} from '@lexical/utils'; -import { - $getSelection, - $isRangeSelection, - CAN_REDO_COMMAND, - CAN_UNDO_COMMAND, - FORMAT_ELEMENT_COMMAND, - FORMAT_TEXT_COMMAND, - REDO_COMMAND, - SELECTION_CHANGE_COMMAND, - UNDO_COMMAND, -} from 'lexical'; -import {useCallback, useEffect, useRef, useState} from 'react'; - -const LowPriority = 1; - -function Divider() { - return
; -} - -export default function ToolbarPlugin() { - const [editor] = useLexicalComposerContext(); - const toolbarRef = useRef(null); - const [canUndo, setCanUndo] = useState(false); - const [canRedo, setCanRedo] = useState(false); - const [isBold, setIsBold] = useState(false); - const [isItalic, setIsItalic] = useState(false); - const [isUnderline, setIsUnderline] = useState(false); - const [isStrikethrough, setIsStrikethrough] = useState(false); - - const $updateToolbar = useCallback(() => { - const selection = $getSelection(); - if ($isRangeSelection(selection)) { - // Update text format - setIsBold(selection.hasFormat('bold')); - setIsItalic(selection.hasFormat('italic')); - setIsUnderline(selection.hasFormat('underline')); - setIsStrikethrough(selection.hasFormat('strikethrough')); - } - }, []); - - useEffect(() => { - return mergeRegister( - editor.registerUpdateListener(({editorState}) => { - editorState.read(() => { - $updateToolbar(); - }); - }), - editor.registerCommand( - SELECTION_CHANGE_COMMAND, - (_payload, _newEditor) => { - $updateToolbar(); - return false; - }, - LowPriority, - ), - editor.registerCommand( - CAN_UNDO_COMMAND, - (payload) => { - setCanUndo(payload); - return false; - }, - LowPriority, - ), - editor.registerCommand( - CAN_REDO_COMMAND, - (payload) => { - setCanRedo(payload); - return false; - }, - LowPriority, - ), - ); - }, [editor, $updateToolbar]); - - return ( -
- - - - - - - - - - - - {' '} -
- ); -} \ No newline at end of file diff --git a/comps/form/field/plugin/TreeViewPlugin.tsx b/comps/form/field/plugin/TreeViewPlugin.tsx deleted file mode 100755 index e904a93..0000000 --- a/comps/form/field/plugin/TreeViewPlugin.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import {TreeView} from '@lexical/react/LexicalTreeView'; - -export default function TreeViewPlugin(): JSX.Element { - const [editor] = useLexicalComposerContext(); - return ( - - ); -} \ No newline at end of file diff --git a/comps/form/field/plugin/richtext.css b/comps/form/field/plugin/richtext.css deleted file mode 100755 index 95c0ca0..0000000 --- a/comps/form/field/plugin/richtext.css +++ /dev/null @@ -1,451 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - - body { - margin: 0; - background: #eee; - font-family: system-ui, -apple-system, BlinkMacSystemFont, '.SFNSText-Regular', - sans-serif; - font-weight: 500; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - - .other h2 { - font-size: 18px; - color: #444; - margin-bottom: 7px; - } - - .other a { - color: #777; - text-decoration: underline; - font-size: 14px; - } - - .other ul { - padding: 0; - margin: 0; - list-style-type: none; - } - - .App { - font-family: sans-serif; - text-align: center; - } - - h1 { - font-size: 24px; - color: #333; - } - - .ltr { - text-align: left; - } - - .rtl { - text-align: right; - } - - .editor-container { - margin: 20px auto 20px auto; - border-radius: 2px; - max-width: 600px; - color: #000; - position: relative; - line-height: 20px; - font-weight: 400; - text-align: left; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - } - - .editor-inner { - background: #fff; - position: relative; - } - - .editor-input { - min-height: 150px; - resize: none; - font-size: 15px; - caret-color: rgb(5, 5, 5); - position: relative; - tab-size: 1; - outline: 0; - padding: 15px 10px; - caret-color: #444; - } - - .editor-placeholder { - color: #999; - overflow: hidden; - position: absolute; - text-overflow: ellipsis; - top: 15px; - left: 10px; - font-size: 15px; - user-select: none; - display: inline-block; - pointer-events: none; - } - - .editor-text-bold { - font-weight: bold; - } - - .editor-text-italic { - font-style: italic; - } - - .editor-text-underline { - text-decoration: underline; - } - - .editor-text-strikethrough { - text-decoration: line-through; - } - - .editor-text-underlineStrikethrough { - text-decoration: underline line-through; - } - - .editor-text-code { - background-color: rgb(240, 242, 245); - padding: 1px 0.25rem; - font-family: Menlo, Consolas, Monaco, monospace; - font-size: 94%; - } - - .editor-link { - color: rgb(33, 111, 219); - text-decoration: none; - } - - .tree-view-output { - display: block; - background: #222; - color: #fff; - padding: 5px; - font-size: 12px; - white-space: pre-wrap; - margin: 1px auto 10px auto; - max-height: 250px; - position: relative; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - overflow: auto; - line-height: 14px; - } - - .editor-code { - background-color: rgb(240, 242, 245); - font-family: Menlo, Consolas, Monaco, monospace; - display: block; - padding: 8px 8px 8px 52px; - line-height: 1.53; - font-size: 13px; - margin: 0; - margin-top: 8px; - margin-bottom: 8px; - tab-size: 2; - /* white-space: pre; */ - overflow-x: auto; - position: relative; - } - - .editor-code:before { - content: attr(data-gutter); - position: absolute; - background-color: #eee; - left: 0; - top: 0; - border-right: 1px solid #ccc; - padding: 8px; - color: #777; - white-space: pre-wrap; - text-align: right; - min-width: 25px; - } - .editor-code:after { - content: attr(data-highlight-language); - top: 0; - right: 3px; - padding: 3px; - font-size: 10px; - text-transform: uppercase; - position: absolute; - color: rgba(0, 0, 0, 0.5); - } - - .editor-tokenComment { - color: slategray; - } - - .editor-tokenPunctuation { - color: #999; - } - - .editor-tokenProperty { - color: #905; - } - - .editor-tokenSelector { - color: #690; - } - - .editor-tokenOperator { - color: #9a6e3a; - } - - .editor-tokenAttr { - color: #07a; - } - - .editor-tokenVariable { - color: #e90; - } - - .editor-tokenFunction { - color: #dd4a68; - } - - .editor-paragraph { - margin: 0; - margin-bottom: 8px; - position: relative; - } - - .editor-paragraph:last-child { - margin-bottom: 0; - } - - .editor-heading-h1 { - font-size: 24px; - color: rgb(5, 5, 5); - font-weight: 400; - margin: 0; - margin-bottom: 12px; - padding: 0; - } - - .editor-heading-h2 { - font-size: 15px; - color: rgb(101, 103, 107); - font-weight: 700; - margin: 0; - margin-top: 10px; - padding: 0; - text-transform: uppercase; - } - - .editor-quote { - margin: 0; - margin-left: 20px; - font-size: 15px; - color: rgb(101, 103, 107); - border-left-color: rgb(206, 208, 212); - border-left-width: 4px; - border-left-style: solid; - padding-left: 16px; - } - - .editor-list-ol { - padding: 0; - margin: 0; - margin-left: 16px; - } - - .editor-list-ul { - padding: 0; - margin: 0; - margin-left: 16px; - } - - .editor-listitem { - margin: 8px 32px 8px 32px; - } - - .editor-nested-listitem { - list-style-type: none; - } - - pre::-webkit-scrollbar { - background: transparent; - width: 10px; - } - - pre::-webkit-scrollbar-thumb { - background: #999; - } - - .debug-timetravel-panel { - overflow: hidden; - padding: 0 0 10px 0; - margin: auto; - display: flex; - } - - .debug-timetravel-panel-slider { - padding: 0; - flex: 8; - } - - .debug-timetravel-panel-button { - padding: 0; - border: 0; - background: none; - flex: 1; - color: #fff; - font-size: 12px; - } - - .debug-timetravel-panel-button:hover { - text-decoration: underline; - } - - .debug-timetravel-button { - border: 0; - padding: 0; - font-size: 12px; - top: 10px; - right: 15px; - position: absolute; - background: none; - color: #fff; - } - - .debug-timetravel-button:hover { - text-decoration: underline; - } - - .toolbar { - display: flex; - margin-bottom: 1px; - background: #fff; - padding: 4px; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - vertical-align: middle; - } - - .toolbar button.toolbar-item { - border: 0; - display: flex; - background: none; - border-radius: 10px; - padding: 8px; - cursor: pointer; - vertical-align: middle; - } - - .toolbar button.toolbar-item:disabled { - cursor: not-allowed; - } - - .toolbar button.toolbar-item.spaced { - margin-right: 2px; - } - - .toolbar button.toolbar-item i.format { - background-size: contain; - display: inline-block; - height: 18px; - width: 18px; - margin-top: 2px; - vertical-align: -0.25em; - display: flex; - opacity: 0.6; - } - - .toolbar button.toolbar-item:disabled i.format { - opacity: 0.2; - } - - .toolbar button.toolbar-item.active { - background-color: rgba(223, 232, 250, 0.3); - } - - .toolbar button.toolbar-item.active i { - opacity: 1; - } - - .toolbar .toolbar-item:hover:not([disabled]) { - background-color: #eee; - } - - .toolbar .divider { - width: 1px; - background-color: #eee; - margin: 0 4px; - } - - .toolbar .toolbar-item .text { - display: flex; - line-height: 20px; - width: 200px; - vertical-align: middle; - font-size: 14px; - color: #777; - text-overflow: ellipsis; - width: 70px; - overflow: hidden; - height: 20px; - text-align: left; - } - - .toolbar .toolbar-item .icon { - display: flex; - width: 20px; - height: 20px; - user-select: none; - margin-right: 8px; - line-height: 16px; - background-size: contain; - } - - i.undo { - background-image: url(icons/arrow-counterclockwise.svg); - } - - i.redo { - background-image: url(icons/arrow-clockwise.svg); - } - - i.bold { - background-image: url(icons/type-bold.svg); - } - - i.italic { - background-image: url(icons/type-italic.svg); - } - - i.underline { - background-image: url(icons/type-underline.svg); - } - - i.strikethrough { - background-image: url(icons/type-strikethrough.svg); - } - - i.left-align { - background-image: url(icons/text-left.svg); - } - - i.center-align { - background-image: url(icons/text-center.svg); - } - - i.right-align { - background-image: url(icons/text-right.svg); - } - - i.justify-align { - background-image: url(icons/justify.svg); - } - \ No newline at end of file diff --git a/comps/form/field/type/TypeCheckbox.tsx b/comps/form/field/type/TypeCheckbox.tsx index c24380f..24a506e 100755 --- a/comps/form/field/type/TypeCheckbox.tsx +++ b/comps/form/field/type/TypeCheckbox.tsx @@ -1,8 +1,7 @@ -import { FC, useEffect } from "react"; -import { FMLocal, FieldLocal, FieldProp } from "../../typings"; import { useLocal } from "@/utils/use-local"; import get from "lodash.get"; -import { DMMF } from "../../../../../typings/runtime/library"; +import { FC, useEffect } from "react"; +import { FMLocal, FieldLocal, FieldProp } from "../../typings"; export const FieldCheckbox: FC<{ field: FieldLocal; diff --git a/comps/form/field/type/TypeMoney.tsx b/comps/form/field/type/TypeMoney.tsx index 65bbd9a..4861b2b 100755 --- a/comps/form/field/type/TypeMoney.tsx +++ b/comps/form/field/type/TypeMoney.tsx @@ -1,10 +1,6 @@ +import { useLocal } from "@/utils/use-local"; import { FC } from "react"; import { FMLocal, FieldLocal } from "../../typings"; -import { useLocal } from "@/utils/use-local"; -import parser from "any-date-parser"; -import { format } from "date-fns"; -import get from "lodash.get"; -import { argv } from "bun"; import { PropTypeText } from "./TypeText"; export const FieldMoney: FC<{ field: FieldLocal; diff --git a/comps/form/field/type/TypeRelation.tsx b/comps/form/field/type/TypeRelation.tsx index 11cacae..ce9fc7e 100755 --- a/comps/form/field/type/TypeRelation.tsx +++ b/comps/form/field/type/TypeRelation.tsx @@ -1,9 +1,9 @@ +import { sortTree } from "@/comps/list/utils/sort-tree"; import { useLocal } from "@/utils/use-local"; import { FC, useEffect } from "react"; import { FMLocal, FieldLocal } from "../../typings"; import { OptionItem, RawDropdown } from "../raw/Dropdown"; import { FieldLoading } from "../raw/FieldLoading"; -import { sortTree } from "@/comps/list/utils/sort-tree"; export type PropTypeRelation = { type: "has-one" | "has-many"; @@ -38,7 +38,7 @@ const HasMany: FC<{ many: [] as { value: string; label: string }[], pk: "", }); - const name = typeof field.name === 'string' ? field.name : field.name(); + const name = field.name; const value = fm.data[name]; field.input = input; field.prop = prop; @@ -100,7 +100,7 @@ const HasOne: FC<{ list: null as null | any[], pk: "", }); - const name = typeof field.name === 'string' ? field.name : field.name(); + const name = field.name; const value = fm.data[name]; field.input = input; field.prop = prop; diff --git a/comps/form/field/type/TypeRichText.tsx b/comps/form/field/type/TypeRichText.tsx index e098851..803da20 100755 --- a/comps/form/field/type/TypeRichText.tsx +++ b/comps/form/field/type/TypeRichText.tsx @@ -1,14 +1,15 @@ -import { FC, useEffect } from "react"; -import { FMLocal, FieldLocal, FieldProp } from "../../typings"; import { useLocal } from "@/utils/use-local"; import Quill from "quill"; import "quill/dist/quill.snow.css"; // Import CSS untuk tema Quill -import get from "lodash.get"; +import { FC, useEffect } from "react"; +import { FMLocal, FieldLocal, FieldProp } from "../../typings"; +import { PropTypeText } from "./TypeText"; + export const FieldRichText: FC<{ field: FieldLocal; fm: FMLocal; - arg: FieldProp; -}> = ({ field, fm, arg }) => { + prop: PropTypeText; +}> = ({ field, fm, prop }) => { const local = useLocal({ ref: null as any, }); diff --git a/comps/form/field/type/TypeSwitch.tsx b/comps/form/field/type/TypeSwitch.tsx index a82823b..ece8816 100755 --- a/comps/form/field/type/TypeSwitch.tsx +++ b/comps/form/field/type/TypeSwitch.tsx @@ -1,20 +1,6 @@ -import { Label } from "@/comps/ui/label"; -import { Switch } from "@/comps/ui/switch"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { Button } from "@/comps/ui/button"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, -} from "@/comps/ui/form"; -import { FC } from "react"; import { useLocal } from "@/utils/use-local"; +import { FC } from "react"; export type PropTypeSwitch = {}; export const FieldTypeSwitch: FC<{ diff --git a/comps/form/field/type/TypeTag.tsx b/comps/form/field/type/TypeTag.tsx index 09d6cb9..af72b61 100755 --- a/comps/form/field/type/TypeTag.tsx +++ b/comps/form/field/type/TypeTag.tsx @@ -1,7 +1,6 @@ -import { FC, useEffect } from "react"; -import { FMLocal, FieldLocal, FieldProp } from "../../typings"; import { useLocal } from "@/utils/use-local"; -import get from "lodash.get"; +import { FC } from "react"; +import { FMLocal, FieldLocal, FieldProp } from "../../typings"; export const FieldTag: FC<{ field: FieldLocal; diff --git a/comps/form/field/type/TypeUpload.tsx b/comps/form/field/type/TypeUpload.tsx index 4364d9d..83bf93f 100755 --- a/comps/form/field/type/TypeUpload.tsx +++ b/comps/form/field/type/TypeUpload.tsx @@ -1,10 +1,7 @@ +import { useLocal } from "@/utils/use-local"; +import get from "lodash.get"; import { FC } from "react"; import { FMLocal, FieldLocal } from "../../typings"; -import { useLocal } from "@/utils/use-local"; -import parser from "any-date-parser"; -import { format } from "date-fns"; -import get from "lodash.get"; -import { argv } from "bun"; import { PropTypeText } from "./TypeText"; export const FieldUpload: FC<{ field: FieldLocal; diff --git a/comps/form/typings.ts b/comps/form/typings.ts index a330a65..7c917bf 100755 --- a/comps/form/typings.ts +++ b/comps/form/typings.ts @@ -23,8 +23,8 @@ export type FMProps = { type FieldType = "-" | "relation" | "switch" | "input" | "single-option" | "multi-option"; export type FieldProp = { - name: string | (() => string); - label: string | (() => string); + name: string; + label: string; desc?: string; props?: any; fm: FMLocal; @@ -60,9 +60,9 @@ export type FMInternal = { error: { readonly object: Record; readonly list: { name: string; error: string[] }[]; - set: (name: string | number | symbol, error: string[]) => void; - get: (name: string | number | symbol) => string[]; - clear: (name?: string | number | symbol) => void; + set: (name: string, error: string[]) => void; + get: (name: string) => string[]; + clear: (name?: string) => void; }; internal: { reload: { diff --git a/comps/form/utils/gen-mitem.ts b/comps/form/utils/gen-mitem.ts deleted file mode 100755 index 5672e17..0000000 --- a/comps/form/utils/gen-mitem.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { newField } from "@/gen/gen_form/new_field"; -import { FMLocal, FieldLocal } from "../typings"; -import get from "lodash.get"; -import { fieldMapping } from "../field/mapping"; -import { createItem } from "@/gen/utils"; - -export const genFieldMitem = (arg: { - _meta: any; - _item: any; - _sync: any; - fm: FMLocal; - field: FieldLocal; -}) => { - const { _meta, _item, _sync, fm, field } = arg; - const m = _meta[_item.id]; - if (m) { - const mitem = m.mitem; - if (mitem) { - const childs = mitem - .get("component") - ?.get("props") - ?.get("child") - ?.get("content") - ?.get("childs"); - let component = fieldMapping[field.type as "text"]; - - if (!component) { - component = fieldMapping["text"]; - } - - if (component) { - const item = createItem({ - component: component as any, - }); - - _sync(childs, [...childs.toJSON(), item]); - } - } - } -}; - -export const updateFieldMItem = (_meta: any, _item: any, _sync: any) => { - const m = _meta[_item.id]; - if (m) { - const mitem = m.mitem; - if (mitem) { - _sync(mitem, _item); - } - } -}; diff --git a/comps/form/utils/use-field.tsx b/comps/form/utils/use-field.tsx index ffaefc1..79119d0 100755 --- a/comps/form/utils/use-field.tsx +++ b/comps/form/utils/use-field.tsx @@ -2,7 +2,10 @@ import { useLocal } from "@/utils/use-local"; import { useEffect } from "react"; import { FieldInternal, FieldProp } from "../typings"; -export const useField = (arg: FieldProp) => { +export const useField = (arg: Omit & { + name: string | (() => string); + label: string | (() => string) +}) => { const field = useLocal>({ status: "init", Child: () => { diff --git a/comps/md/MDAction.tsx b/comps/md/MDAction.tsx index 8fba598..3e52000 100755 --- a/comps/md/MDAction.tsx +++ b/comps/md/MDAction.tsx @@ -2,7 +2,7 @@ import { useLocal } from "@/utils/use-local"; import { FC, Fragment, isValidElement } from "react"; import { getProp } from "./utils/get-prop"; import { MDActions, MDLocal } from "./utils/typings"; - + export const MDAction: FC<{ md: MDLocal; PassProp: any; child: any }> = ({ md, PassProp, diff --git a/comps/md/MasterDetail.tsx b/comps/md/MasterDetail.tsx index 7c03ea3..3f28822 100755 --- a/comps/md/MasterDetail.tsx +++ b/comps/md/MasterDetail.tsx @@ -37,97 +37,98 @@ export const MasterDetail: FC<{ gen_table, on_init, }) => { - let isGenerate = false as Boolean; + let isGenerate = false as Boolean; - try { - if (!get(w.md_internal, _item.id)) w.md_internal = { + try { + if (!get(w.md_internal, _item.id)) + w.md_internal = { ...w.md_internal, - [_item.id]: _item + [_item.id]: _item, }; - isGenerate = false; - if (w.generating_prasi_md["master_detail"]) { - isGenerate = true; - } - } catch (ex) { } - const _ref = useRef({ PassProp, child }); - const md = useLocal({ - name, - actions: [], - breadcrumb: [], - selected: null, - tab: { - active: "", - list: [], - }, - internal: { action_should_refresh: true }, - childs: {}, - props: { - mode, - show_head, - tab_mode, - editor_tab, - gen_fields, - gen_table, - on_init, - }, - params: { - hash: {}, - tabs: {}, - parse: () => { - masterDetailParseParams(md); - }, - apply: () => { - masterDetailApplyParams(md); - }, - }, - master: { internal: null, render() { } }, - panel: { - size: 25, - min_size: 0, - }, - }); - - - const local = useLocal({ init: false }); - if (isEditor) { - md.props.mode = mode; - md.props.show_head = show_head; - md.props.tab_mode = tab_mode; - md.props.editor_tab = editor_tab; - md.props.gen_fields = gen_fields; - md.props.gen_table = gen_table; - md.props.on_init = on_init; + isGenerate = false; + if (w.generating_prasi_md["master_detail"]) { + isGenerate = true; } - _ref.current.PassProp = PassProp; - _ref.current.child = child; + } catch (ex) {} - useEffect(() => { - local.init = false; - local.render(); - }, [editor_tab]); + const _ref = useRef({ PassProp, child }); + const md = useLocal({ + name, + actions: [], + breadcrumb: [], + selected: null, + tab: { + active: "", + list: [], + }, + internal: { action_should_refresh: true }, + childs: {}, + props: { + mode, + show_head, + tab_mode, + editor_tab, + gen_fields, + gen_table, + on_init, + }, + params: { + hash: {}, + tabs: {}, + parse: () => { + masterDetailParseParams(md); + }, + apply: () => { + masterDetailApplyParams(md); + }, + }, + master: { internal: null, render() {} }, + panel: { + size: 25, + min_size: 0, + }, + }); - refreshBread(md); - if (!local.init || isEditor) { - local.init = true; - masterDetailInit(md, child, editor_tab); - masterDetailSelected(md); - } - if (isGenerate) return <>Generating ...; - return ( -
- {md.props.show_head === "always" && ( - - )} - {md.props.mode === "full" && } - {md.props.mode === "v-split" && } - {md.props.mode === "h-split" && } -
- ); - }; + const local = useLocal({ init: false }); + if (isEditor) { + md.props.mode = mode; + md.props.show_head = show_head; + md.props.tab_mode = tab_mode; + md.props.editor_tab = editor_tab; + md.props.gen_fields = gen_fields; + md.props.gen_table = gen_table; + md.props.on_init = on_init; + } + _ref.current.PassProp = PassProp; + _ref.current.child = child; + + useEffect(() => { + local.init = false; + local.render(); + }, [editor_tab]); + + refreshBread(md); + if (!local.init || isEditor) { + local.init = true; + masterDetailInit(md, child, editor_tab); + masterDetailSelected(md); + } + if (isGenerate) return <>Generating ...; + return ( +
+ {md.props.show_head === "always" && ( + + )} + {md.props.mode === "full" && } + {md.props.mode === "v-split" && } + {md.props.mode === "h-split" && } +
+ ); +}; const ModeFull: FC<{ md: MDLocal; mdr: MDRef }> = ({ md, mdr }) => { if (should_show_tab(md)) { diff --git a/comps/md/utils/typings.ts b/comps/md/utils/typings.ts index f7cbabc..b5a92b4 100755 --- a/comps/md/utils/typings.ts +++ b/comps/md/utils/typings.ts @@ -127,4 +127,8 @@ export const MasterDetailType = `const md = { md?: md; } >; + panel: { + size: number; + min_size: number; + }; };`; diff --git a/comps/ui/form.tsx b/comps/ui/form.tsx deleted file mode 100755 index 2ad12e2..0000000 --- a/comps/ui/form.tsx +++ /dev/null @@ -1,177 +0,0 @@ -import * as React from "react"; -import * as LabelPrimitive from "@radix-ui/react-label"; -import { Slot } from "@radix-ui/react-slot"; -import { - Controller, - ControllerProps, - FieldPath, - FieldValues, - FormProvider, - useFormContext, -} from "react-hook-form"; - -import { cn } from "@/utils"; -import { Label } from "@/comps/ui/label"; - -const Form = FormProvider; - -type FormFieldContextValue< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath -> = { - name: TName; -}; - -const FormFieldContext = React.createContext( - {} as FormFieldContextValue -); - -const FormField = < - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath ->({ - ...props -}: ControllerProps) => { - return ( - - - - ); -}; - -const useFormField = () => { - const fieldContext = React.useContext(FormFieldContext); - const itemContext = React.useContext(FormItemContext); - const { getFieldState, formState } = useFormContext(); - - const fieldState = getFieldState(fieldContext.name, formState); - - if (!fieldContext) { - throw new Error("useFormField should be used within "); - } - - const { id } = itemContext; - - return { - id, - name: fieldContext.name, - formItemId: `${id}-form-item`, - formDescriptionId: `${id}-form-item-description`, - formMessageId: `${id}-form-item-message`, - ...fieldState, - }; -}; - -type FormItemContextValue = { - id: string; -}; - -const FormItemContext = React.createContext( - {} as FormItemContextValue -); - -const FormItem = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { - const id = React.useId(); - - return ( - -
- - ); -}); -FormItem.displayName = "FormItem"; - -const FormLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - const { error, formItemId } = useFormField(); - - return ( -