UNPKG

@canard/schema-form

Version:

React-based component library that renders forms based on JSON Schema with plugin system support for validators and UI components

109 lines (108 loc) 2.95 kB
import { type ForwardedRef, type ReactNode } from 'react'; import type { AllowedValue, InferValueType, JsonSchema } from '../../types'; import type { FormHandle, FormProps } from './type'; /** * Schema-driven form component that generates and manages forms based on JSON Schema. * * @typeParam Schema - The JSON Schema type that defines form structure * @typeParam Value - The inferred value type from the schema * * @example * Basic usage with automatic field generation: * ```tsx * const schema = { * type: 'object', * properties: { * username: { type: 'string', minLength: 3 }, * email: { type: 'string', format: 'email' }, * age: { type: 'number', minimum: 18 } * }, * required: ['username', 'email'] * }; * * function MyForm() { * const [value, setValue] = useState({}); * const formRef = useRef<FormHandle>(); * * const handleSubmit = async (data) => { * await api.saveUser(data); * }; * * return ( * <Form * ref={formRef} * jsonSchema={schema} * onChange={setValue} * onSubmit={handleSubmit} * showError={ShowError.Touched} * /> * ); * } * ``` * * @example * Custom layout with composition: * ```tsx * <Form jsonSchema={schema} defaultValue={initialData}> * <div className="form-section"> * <h3>Account Information</h3> * <Form.Group path="/username" /> * <Form.Group path="/email" /> * </div> * <div className="form-section"> * <h3>Personal Details</h3> * <Form.Label path="/age" className="required" /> * <Form.Input path="/age" min={18} max={100} /> * <Form.Error path="/age" className="error-text" /> * </div> * </Form> * ``` * * @example * Dynamic form with conditional fields: * ```tsx * <Form jsonSchema={schema}> * {({ value, errors, node }) => ( * <> * <Form.Input path="/accountType" /> * {value?.accountType === 'business' && ( * <> * <Form.Input path="/companyName" /> * <Form.Input path="/taxId" /> * </> * )} * <button * onClick={() => node?.validate()} * disabled={errors?.length > 0} * > * Submit * </button> * </> * )} * </Form> * ``` * * @example * Using ref for imperative actions: * ```tsx * const formRef = useRef<FormHandle>(); * * // Focus specific field * formRef.current?.focus('/email'); * * // Validate programmatically * const errors = await formRef.current?.validate(); * * // Set value with options * formRef.current?.setValue( * { email: 'new@email.com' }, * { merge: true, validate: true } * ); * * // Submit form programmatically * await formRef.current?.submit(); * ``` */ export declare const Form: <Schema extends JsonSchema, Value extends AllowedValue = InferValueType<Schema>>(props: FormProps<Schema, Value> & { ref?: ForwardedRef<FormHandle<Schema, Value>>; }) => ReactNode;