import type { JsonSchema } from "json-schema-library"; import { type ChangeEvent, type ComponentPropsWithoutRef, type ElementType, type ReactNode, useEffect, useId, } from "react"; import ErrorBoundary from "ui/components/display/ErrorBoundary"; import * as Formy from "ui/components/form/Formy"; import { useEvent } from "ui/hooks/use-event"; import { ArrayField } from "./ArrayField"; import { FieldWrapper, type FieldwrapperProps } from "./FieldWrapper"; import { useDerivedFieldContext, useFormValue } from "./Form"; import { ObjectField } from "./ObjectField"; import { coerce, firstDefined, isType, isTypeSchema } from "./utils"; export type FieldProps = { onChange?: (e: ChangeEvent) => void; placeholder?: string; disabled?: boolean; inputProps?: Partial; } & Omit; export const Field = (props: FieldProps) => { return ( ); }; export const HiddenField = ({ as = "div", className, ...props }: FieldProps & { as?: ElementType; className?: string }) => { const Component = as; return ( ); }; const fieldErrorBoundary = ({ name }: FieldProps) => ({ error }: { error: Error }) => (
         Field "{name}" error: {error.message}
      
); const FieldImpl = ({ name, onChange, placeholder, required: _required, inputProps, ...props }: FieldProps) => { const { path, setValue, schema, ...ctx } = useDerivedFieldContext(name); const id = `${name}-${useId()}`; const required = typeof _required === "boolean" ? _required : ctx.required; if (!schema) return (
            [Field] {path} has no schema ({JSON.stringify(schema)})
         
); if (isType(schema.type, "object")) { return ; } if (isType(schema.type, "array")) { return ; } // account for `defaultValue` // like useEffect(() => { if (inputProps?.defaultValue) { setValue(path, inputProps.defaultValue); } }, [inputProps?.defaultValue]); const disabled = firstDefined( ctx.readOnly, inputProps?.disabled, props.disabled, schema.readOnly, "const" in schema, false, ); const handleChange = useEvent((e: ChangeEvent) => { const value = coerce(e.target.value, schema as any, { required }); if (typeof value === "undefined" && !required && ctx.options?.keepEmpty !== true) { ctx.deleteValue(path); } else { setValue(path, value); } }); return ( ); }; export const Pre = ({ children }) => (
      {children}
   
); export type FieldComponentProps = { schema: JsonSchema; render?: (props: Omit) => ReactNode; "data-testId"?: string; } & ComponentPropsWithoutRef<"input">; export const FieldComponent = ({ schema, render, ..._props }: FieldComponentProps) => { const { value } = useFormValue(_props.name!, { strict: true }); if (!isTypeSchema(schema)) return null; const props = { ..._props, // allow override value: typeof _props.value !== "undefined" ? _props.value : value, placeholder: (_props.placeholder ?? typeof schema.default !== "undefined") ? String(schema.default) : "", }; if (render) return render({ schema, ...props }); if (schema.enum) { return ; } if (isType(schema.type, ["number", "integer"])) { const additional = { min: schema.minimum, max: schema.maximum, step: schema.multipleOf, }; return ; } if (isType(schema.type, "boolean")) { 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 ; };