From 2e3ee65aa7ff0a1fb87bb62729bc5ad9c3e65f26 Mon Sep 17 00:00:00 2001 From: dswbx Date: Fri, 7 Feb 2025 17:28:01 +0100 Subject: [PATCH] added more input field types and improved typing --- .../form/json-schema-form/ArrayField.tsx | 3 +- .../form/json-schema-form/Field.tsx | 55 +++++++++++++++- .../form/json-schema-form/FieldWrapper.tsx | 66 ++++++++++++------- .../components/form/json-schema-form/Form.tsx | 17 ++--- .../components/form/json-schema-form/utils.ts | 2 +- .../routes/test/tests/json-schema-form3.tsx | 51 +++++++++++++- 6 files changed, 153 insertions(+), 41 deletions(-) diff --git a/app/src/ui/components/form/json-schema-form/ArrayField.tsx b/app/src/ui/components/form/json-schema-form/ArrayField.tsx index 47f3166..e48185d 100644 --- a/app/src/ui/components/form/json-schema-form/ArrayField.tsx +++ b/app/src/ui/components/form/json-schema-form/ArrayField.tsx @@ -100,7 +100,7 @@ const ArrayIterator = memo( ({ name, children }: any) => { return children(useFormValue(name)); }, - (prev, next) => prev.value.length === next.value.length + (prev, next) => prev.value?.length === next.value?.length ); const ArrayAdd = ({ schema, path }: { schema: JsonSchema; path: string }) => { @@ -114,7 +114,6 @@ const ArrayAdd = ({ schema, path }: { schema: JsonSchema; path: string }) => { const itemsMultiSchema = getMultiSchema(schema.items); function handleAdd(template?: any) { - //const currentIndex = value?.length ?? 0; const newPointer = `${path}/${currentIndex}`.replace(/\/+/g, "/"); setValue(newPointer, template ?? ctx.lib.getTemplate(undefined, schema!.items)); } diff --git a/app/src/ui/components/form/json-schema-form/Field.tsx b/app/src/ui/components/form/json-schema-form/Field.tsx index f8c9ef7..50cf6a7 100644 --- a/app/src/ui/components/form/json-schema-form/Field.tsx +++ b/app/src/ui/components/form/json-schema-form/Field.tsx @@ -81,12 +81,61 @@ export const FieldComponent = ({ } if (isType(schema.type, ["number", "integer"])) { - return ; + const additional = { + min: schema.minimum, + max: schema.maximum, + step: schema.multipleOf + }; + + return ( + + ); } if (isType(schema.type, "boolean")) { - return ; + return ; } - return ; + if (isType(schema.type, "string") && schema.format === "date-time") { + const value = props.value ? new Date(props.value as string).toISOString().slice(0, 16) : ""; + return ( + { + const date = new Date(e.target.value); + props.onChange?.({ + // @ts-ignore + target: { value: date.toISOString() } + }); + }} + /> + ); + } + + if (isType(schema.type, "string") && schema.format === "date") { + return ; + } + + const additional = { + maxLength: schema.maxLength, + minLength: schema.minLength, + pattern: schema.pattern + } as any; + + if (schema.format) { + if (["password", "hidden", "url", "email", "tel"].includes(schema.format)) { + additional.type = schema.format; + } + } + + return ; }; diff --git a/app/src/ui/components/form/json-schema-form/FieldWrapper.tsx b/app/src/ui/components/form/json-schema-form/FieldWrapper.tsx index d1ae568..58fa065 100644 --- a/app/src/ui/components/form/json-schema-form/FieldWrapper.tsx +++ b/app/src/ui/components/form/json-schema-form/FieldWrapper.tsx @@ -5,7 +5,11 @@ import { Children, type ReactElement, type ReactNode, cloneElement, isValidEleme import { IconButton } from "ui/components/buttons/IconButton"; import { JsonViewer } from "ui/components/code/JsonViewer"; import * as Formy from "ui/components/form/Formy"; -import { useFormError } from "ui/components/form/json-schema-form/Form"; +import { + useFormContext, + useFormError, + useFormValue +} from "ui/components/form/json-schema-form/Form"; import { getLabel } from "./utils"; export type FieldwrapperProps = { @@ -24,7 +28,6 @@ export function FieldWrapper({ label: _label, required, schema, - debug, wrapper, hidden, children @@ -41,29 +44,7 @@ export function FieldWrapper({ as={wrapper === "fieldset" ? "fieldset" : "div"} className={hidden ? "hidden" : "relative"} > - {debug && ( -
- {/* @todo: use radix */} - - - - - - - - -
- )} + {label && ( ); } + +const FieldDebug = ({ + name, + schema, + required +}: Pick) => { + const { options } = useFormContext(); + if (!options?.debug) return null; + const { value } = useFormValue(name); + const errors = useFormError(name, { strict: true }); + + return ( +
+ {/* @todo: use radix */} + + + + + + + + +
+ ); +}; diff --git a/app/src/ui/components/form/json-schema-form/Form.tsx b/app/src/ui/components/form/json-schema-form/Form.tsx index a2cd7bb..e7876bb 100644 --- a/app/src/ui/components/form/json-schema-form/Form.tsx +++ b/app/src/ui/components/form/json-schema-form/Form.tsx @@ -45,32 +45,32 @@ type FormState = { export type FormProps< Schema extends JSONSchema = JSONSchema, - Data = Schema extends JSONSchema ? FromSchema : any -> = Omit, "onChange"> & { + Data = Schema extends JSONSchema ? FromSchema : any, + InitialData = Schema extends JSONSchema ? FromSchema : any +> = Omit, "onChange" | "onSubmit"> & { schema: Schema; validateOn?: "change" | "submit"; - initialValues?: Partial; initialOpts?: LibTemplateOptions; ignoreKeys?: string[]; onChange?: (data: Partial, name: string, value: any) => void; - onSubmit?: (data: Partial) => void | Promise; + onSubmit?: (data: Data) => void | Promise; onInvalidSubmit?: (errors: JsonError[], data: Partial) => void; hiddenSubmit?: boolean; options?: { debug?: boolean; keepEmpty?: boolean; }; + initialValues?: InitialData; }; export type FormContext = { - data: Data; setData: (data: Data) => void; setValue: (pointer: string, value: any) => void; deleteValue: (pointer: string) => void; errors: JsonError[]; dirty: boolean; submitting: boolean; - schema: JSONSchema; + schema: LibJsonSchema; lib: Draft2019; options: FormProps["options"]; root: string; @@ -82,7 +82,7 @@ FormContext.displayName = "FormContext"; export function Form< Schema extends JSONSchema = JSONSchema, - Data = Schema extends JSONSchema ? FromSchema : any + Data = Schema extends JSONSchema ? FromSchema : any >({ schema: _schema, initialValues: _initialValues, @@ -126,7 +126,7 @@ export function Form< try { const { data, errors } = validate(); if (errors.length === 0) { - await onSubmit(data); + await onSubmit(data as Data); } else { console.log("invalid", errors); onInvalidSubmit?.(errors, data); @@ -200,6 +200,7 @@ export function Form<
{children ? children : } + {options?.debug && } {hiddenSubmit && (