UNPKG

@react-formgen/json-schema

Version:

A headless, type-safe, customizable, and super simple React form generator.

313 lines (312 loc) 11.9 kB
import { ErrorObject } from "ajv"; import { JSONSchema7 } from "json-schema"; /** * Represents the props for the Form component. * * @property {JSONSchema7 | FormgenJSONSchema7} schema - The JSON Schema for the form * @property {{ [key: string]: unknown }} [initialData] - Initial form data * @property {(data: { [key: string]: unknown }) => void} [onSubmit] - Called on successful form submission * @property {(errors: ErrorObject[], data?: { [key: string]: unknown }) => void} [onError] - Called when form has validation errors * @property {Templates} templates - Custom templates used in rendering type-specific components * @property {React.FC<FormRootProps>} formRoot - Custom form root component * @property {React.FC<RenderTemplateProps>} [renderTemplate] - Custom template renderer override * @property {boolean} [readonly] - Whether to render the form in readonly mode * @property {boolean} [enableDevtools] - Whether to enable Zustand devtools for debugging */ export type FormProps = { schema: JSONSchema7 | FormgenJSONSchema7; initialData?: { [key: string]: unknown; }; onSubmit?: (data: { [key: string]: unknown; }) => void; onError?: (errors: ErrorObject[], data?: { [key: string]: unknown; }) => void; templates: Templates; formRoot: React.FC<FormRootProps>; renderTemplate?: React.FC<RenderTemplateProps>; readonly?: boolean; enableDevtools?: boolean; }; /** * Represents the props for the FormProvider component. * * @property {JSONSchema7 | FormgenJSONSchema7} schema - The JSON Schema for the form * @property {{ [key: string]: unknown }} [initialData] - Initial form data * @property {React.ReactNode} children - Child components that will have access to the form context * @property {Templates} templates - Custom templates used in rendering type-specific components * @property {boolean} [readonly] - Whether to render the form in readonly mode * @property {React.FC<RenderTemplateProps>} [renderTemplate] - Optional custom render template function * @property {boolean} [enableDevtools] - Whether to enable Zustand devtools for debugging */ export type FormProviderProps = { schema: JSONSchema7 | FormgenJSONSchema7; initialData?: { [key: string]: unknown; }; children: React.ReactNode; templates: Templates; readonly?: boolean; renderTemplate?: React.FC<RenderTemplateProps>; enableDevtools?: boolean; }; /** * Represents the props for the FormRoot component. * This is the component responsible for rendering the form container, handling form submission, * and displaying validation errors. * * @property {(data: { [key: string]: unknown }) => void} onSubmit - Called on successful form submission * @property {(errors: ErrorObject[], data?: { [key: string]: unknown }) => void} onError - Called when form has validation errors */ export type FormRootProps = { onSubmit: (data: { [key: string]: unknown; }) => void; onError: (errors: ErrorObject[], data?: { [key: string]: unknown; }) => void; }; /** * Represents the UI schema for a property. * This can be used to provide UI-specific configuration for a schema property. * * @property {string} component - The component to use for the property * @property {Record<string, unknown>} [props] - The props to pass to the component */ export interface UISchema { component: string; props?: Record<string, unknown>; } /** * Represents an extended JSONSchema7 with additional properties for customizing forms. * This adds form-specific extensions to the standard JSON Schema. * * @extends {Omit<JSONSchema7, "properties" | "definitions" | "items">} * @property {UISchema} [uiSchema] - UI-specific configuration * @property {Record<string, FormgenJSONSchema7>} [properties] - Object properties * @property {Record<string, FormgenJSONSchema7>} [definitions] - Schema definitions * @property {FormgenJSONSchema7 | FormgenJSONSchema7[]} [items] - Array items schema with uiSchema support */ export interface FormgenJSONSchema7 extends Omit<JSONSchema7, "properties" | "definitions" | "items"> { uiSchema?: UISchema; properties?: Record<string, FormgenJSONSchema7>; definitions?: Record<string, FormgenJSONSchema7>; items?: FormgenJSONSchema7 | FormgenJSONSchema7[]; } /** * Custom OneOf type for strings. * Used in the StringSchema to provide multiple-choice options with labels. * * @property {string} const - The actual string value * @property {string} [title] - Display label for the option * @property {string} [description] - Optional description for the option */ export type StringOneOf = { const: string; title?: string; description?: string; }; /** * Represents a base string schema. * This is used as a base for the StringSchema type, for instances where all constraints are not needed. * * @extends {Omit<JSONSchema7, "type">} * @property {"string"} type - The schema type */ export interface BaseStringSchema extends Omit<JSONSchema7, "type"> { type: "string"; } /** * Represents a fully-featured string schema with additional UI options. * Use this type when implementing your StringTemplate component. * * @extends {Omit<FormgenJSONSchema7, "type" | "enum" | "oneOf">} * @property {"string"} type - The schema type * @property {string[]} [enum] - Dropdown options * @property {StringOneOf[]} [oneOf] - Multiple-choice options with labels * @property {UISchema} [uiSchema] - UI-specific configuration */ export interface StringSchema extends Omit<FormgenJSONSchema7, "type" | "enum" | "oneOf"> { type: "string"; enum?: string[]; oneOf?: StringOneOf[]; uiSchema?: UISchema; } /** * Custom OneOf type for numbers. * Used in the NumberSchema to provide multiple-choice options with labels. * * @property {number} const - The actual numeric value * @property {string} [title] - Display label for the option * @property {string} [description] - Optional description for the option */ export type NumberOneOf = { const: number; title?: string; description?: string; }; /** * Represents a base number schema. * This is used as a base for the NumberSchema type, for instances where all constraints are not needed. * * @extends {Omit<JSONSchema7, "type">} * @property {"number" | "integer"} type - The schema type */ export interface BaseNumberSchema extends Omit<JSONSchema7, "type"> { type: "number" | "integer"; } /** * Represents a fully-featured number schema with additional UI options. * Use this type when implementing your NumberTemplate component. * * @extends {Omit<FormgenJSONSchema7, "type" | "enum" | "oneOf">} * @property {"number" | "integer"} type - The schema type * @property {number[]} [enum] - Dropdown options * @property {NumberOneOf[]} [oneOf] - Multiple-choice options with labels * @property {UISchema} [uiSchema] - UI-specific configuration */ export interface NumberSchema extends Omit<FormgenJSONSchema7, "type" | "enum" | "oneOf"> { type: "number" | "integer"; enum?: number[]; oneOf?: NumberOneOf[]; uiSchema?: UISchema; } /** * Custom OneOf type for booleans. * Used in the BooleanSchema to provide labeled boolean options (e.g., "Yes"/"No"). * * @property {boolean} const - The actual boolean value * @property {string} [title] - Display label for the option */ export type BooleanOneOf = { const: boolean; title?: string; }; /** * Represents a base boolean schema. * This is used as a base for the BooleanSchema type, for instances where all constraints are not needed. * * @extends {Omit<JSONSchema7, "type">} * @property {"boolean"} type - The schema type */ export interface BaseBooleanSchema extends Omit<JSONSchema7, "type"> { type: "boolean"; } /** * Represents a fully-featured boolean schema with additional UI options. * Use this type when implementing your BooleanTemplate component. * * @extends {Omit<FormgenJSONSchema7, "type" | "oneOf">} * @property {"boolean"} type - The schema type * @property {BooleanOneOf[]} [oneOf] - Options for rendering as radio buttons with labels * @property {UISchema} [uiSchema] - UI-specific configuration */ export interface BooleanSchema extends Omit<FormgenJSONSchema7, "type" | "oneOf"> { type: "boolean"; oneOf?: BooleanOneOf[]; uiSchema?: UISchema; } /** * Represents a base object schema. * This is used as a base for the ObjectSchema type, for instances where all constraints are not needed. * * @extends {Omit<JSONSchema7, "type">} * @property {"object"} type - The schema type */ export interface BaseObjectSchema extends Omit<JSONSchema7, "type"> { type: "object"; } /** * Represents a fully-featured object schema with additional UI options. * Use this type when implementing your ObjectTemplate component. * * @extends {Omit<FormgenJSONSchema7, "type">} * @property {"object"} type - The schema type * @property {UISchema} [uiSchema] - UI-specific configuration */ export interface ObjectSchema extends Omit<FormgenJSONSchema7, "type"> { type: "object"; uiSchema?: UISchema; } /** * Represents a base array schema. * This is used as a base for the ArraySchema type, for instances where all constraints are not needed. * * @extends {Omit<JSONSchema7, "type">} * @property {"array"} type - The schema type */ export interface BaseArraySchema extends Omit<JSONSchema7, "type"> { type: "array"; } /** * Represents a fully-featured array schema with additional UI options. * Use this type when implementing your ArrayTemplate component. * * @extends {Omit<FormgenJSONSchema7, "type">} * @property {"array"} type - The schema type * @property {UISchema} [uiSchema] - UI-specific configuration */ export interface ArraySchema extends Omit<FormgenJSONSchema7, "type"> { type: "array"; uiSchema?: UISchema; } /** * Represents the custom templates for each schema type. * You MUST provide implementations for all of these template components. * * @property {React.FC<{ schema: StringSchema; path: string[] }>} StringTemplate - Template for string-schema * @property {React.FC<{ schema: NumberSchema; path: string[] }>} NumberTemplate - Template for number-schema * @property {React.FC<{ schema: BooleanSchema; path: string[] }>} BooleanTemplate - Template for boolean-schema * @property {React.FC<{ schema: ObjectSchema; path: string[] }>} ObjectTemplate - Template for object-schema * @property {React.FC<{ schema: ArraySchema; path: string[] }>} ArrayTemplate - Template for array-schema */ export type Templates = { StringTemplate: React.FC<{ schema: StringSchema; path: string[]; }> | React.FC<{ schema: BaseStringSchema; path: string[]; }>; NumberTemplate: React.FC<{ schema: NumberSchema; path: string[]; }> | React.FC<{ schema: BaseNumberSchema; path: string[]; }>; BooleanTemplate: React.FC<{ schema: BooleanSchema; path: string[]; }> | React.FC<{ schema: BaseBooleanSchema; path: string[]; }>; ObjectTemplate: React.FC<{ schema: ObjectSchema; path: string[]; }> | React.FC<{ schema: BaseObjectSchema; path: string[]; }>; ArrayTemplate: React.FC<{ schema: ArraySchema; path: string[]; }> | React.FC<{ schema: BaseArraySchema; path: string[]; }>; }; /** * Props for the RenderTemplate component. * This component is responsible for rendering the correct template based on the schema type. * * @property {JSONSchema7 | FormgenJSONSchema7} schema - The schema to render * @property {string[]} path - The path to the property corresponding to the schema */ export interface RenderTemplateProps { schema: JSONSchema7 | FormgenJSONSchema7; path: string[]; }