mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 12:37:20 +00:00
added more input field types and improved typing
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
@@ -81,12 +81,61 @@ export const FieldComponent = ({
|
||||
}
|
||||
|
||||
if (isType(schema.type, ["number", "integer"])) {
|
||||
return <Formy.Input type="number" id={props.name} {...props} value={props.value ?? ""} />;
|
||||
const additional = {
|
||||
min: schema.minimum,
|
||||
max: schema.maximum,
|
||||
step: schema.multipleOf
|
||||
};
|
||||
|
||||
return (
|
||||
<Formy.Input
|
||||
type="number"
|
||||
id={props.name}
|
||||
{...props}
|
||||
value={props.value ?? ""}
|
||||
{...additional}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (isType(schema.type, "boolean")) {
|
||||
return <Formy.Switch id={props.name} {...(props as any)} checked={value as any} />;
|
||||
return <Formy.Switch id={props.name} {...(props as any)} checked={value === true} />;
|
||||
}
|
||||
|
||||
return <Formy.Input id={props.name} {...props} value={props.value ?? ""} />;
|
||||
if (isType(schema.type, "string") && schema.format === "date-time") {
|
||||
const value = props.value ? new Date(props.value as string).toISOString().slice(0, 16) : "";
|
||||
return (
|
||||
<Formy.DateInput
|
||||
id={props.name}
|
||||
{...props}
|
||||
value={value}
|
||||
type="datetime-local"
|
||||
onChange={(e) => {
|
||||
const date = new Date(e.target.value);
|
||||
props.onChange?.({
|
||||
// @ts-ignore
|
||||
target: { value: date.toISOString() }
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (isType(schema.type, "string") && schema.format === "date") {
|
||||
return <Formy.DateInput id={props.name} {...props} value={props.value ?? ""} />;
|
||||
}
|
||||
|
||||
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 <Formy.Input id={props.name} {...props} value={props.value ?? ""} {...additional} />;
|
||||
};
|
||||
|
||||
@@ -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 && (
|
||||
<div className="absolute right-0 top-0">
|
||||
{/* @todo: use radix */}
|
||||
<Popover>
|
||||
<Popover.Target>
|
||||
<IconButton Icon={IconBug} size="xs" className="opacity-30" />
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown>
|
||||
<JsonViewer
|
||||
json={{
|
||||
...(typeof debug === "object" ? debug : {}),
|
||||
name,
|
||||
required,
|
||||
schema,
|
||||
errors
|
||||
}}
|
||||
expand={6}
|
||||
className="p-0"
|
||||
/>
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
<FieldDebug name={name} schema={schema} required={required} />
|
||||
|
||||
{label && (
|
||||
<Formy.Label
|
||||
@@ -98,3 +79,38 @@ export function FieldWrapper({
|
||||
</Formy.Group>
|
||||
);
|
||||
}
|
||||
|
||||
const FieldDebug = ({
|
||||
name,
|
||||
schema,
|
||||
required
|
||||
}: Pick<FieldwrapperProps, "name" | "schema" | "required">) => {
|
||||
const { options } = useFormContext();
|
||||
if (!options?.debug) return null;
|
||||
const { value } = useFormValue(name);
|
||||
const errors = useFormError(name, { strict: true });
|
||||
|
||||
return (
|
||||
<div className="absolute right-0 top-0">
|
||||
{/* @todo: use radix */}
|
||||
<Popover>
|
||||
<Popover.Target>
|
||||
<IconButton Icon={IconBug} size="xs" className="opacity-30" />
|
||||
</Popover.Target>
|
||||
<Popover.Dropdown>
|
||||
<JsonViewer
|
||||
json={{
|
||||
name,
|
||||
value,
|
||||
required,
|
||||
schema,
|
||||
errors
|
||||
}}
|
||||
expand={6}
|
||||
className="p-0"
|
||||
/>
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -45,32 +45,32 @@ type FormState<Data = any> = {
|
||||
|
||||
export type FormProps<
|
||||
Schema extends JSONSchema = JSONSchema,
|
||||
Data = Schema extends JSONSchema ? FromSchema<JSONSchema> : any
|
||||
> = Omit<ComponentPropsWithoutRef<"form">, "onChange"> & {
|
||||
Data = Schema extends JSONSchema ? FromSchema<Schema> : any,
|
||||
InitialData = Schema extends JSONSchema ? FromSchema<Schema> : any
|
||||
> = Omit<ComponentPropsWithoutRef<"form">, "onChange" | "onSubmit"> & {
|
||||
schema: Schema;
|
||||
validateOn?: "change" | "submit";
|
||||
initialValues?: Partial<Data>;
|
||||
initialOpts?: LibTemplateOptions;
|
||||
ignoreKeys?: string[];
|
||||
onChange?: (data: Partial<Data>, name: string, value: any) => void;
|
||||
onSubmit?: (data: Partial<Data>) => void | Promise<void>;
|
||||
onSubmit?: (data: Data) => void | Promise<void>;
|
||||
onInvalidSubmit?: (errors: JsonError[], data: Partial<Data>) => void;
|
||||
hiddenSubmit?: boolean;
|
||||
options?: {
|
||||
debug?: boolean;
|
||||
keepEmpty?: boolean;
|
||||
};
|
||||
initialValues?: InitialData;
|
||||
};
|
||||
|
||||
export type FormContext<Data> = {
|
||||
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<JSONSchema> : any
|
||||
Data = Schema extends JSONSchema ? FromSchema<Schema> : 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<
|
||||
<form {...props} ref={formRef} onSubmit={handleSubmit}>
|
||||
<FormContext.Provider value={context}>
|
||||
{children ? children : <Field name="" />}
|
||||
{options?.debug && <FormDebug />}
|
||||
</FormContext.Provider>
|
||||
{hiddenSubmit && (
|
||||
<button style={{ visibility: "hidden" }} type="submit">
|
||||
|
||||
@@ -141,7 +141,7 @@ export function isRequired(pointer: string, schema: JsonSchema, data?: any) {
|
||||
const lib = new Draft2019(schema as any);
|
||||
|
||||
const childSchema = lib.getSchema({ pointer, data });
|
||||
if (typeof childSchema === "object" && ("const" in childSchema || "enum" in childSchema)) {
|
||||
if (typeof childSchema === "object" && "const" in childSchema) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user