@canard/schema-form
Version:
React-based component library that renders forms based on JSON Schema with plugin system support for validators and UI components
183 lines (182 loc) • 5.91 kB
TypeScript
import { type ComponentType, type PropsWithChildren } from 'react';
import type { Dictionary } from '../../@aileron/declare';
import type { ValidationMode } from '../../core';
import type { FormTypeInputDefinition, FormTypeRendererProps, FormatError, ShowError, ValidatorFactory } from '../../types';
export interface ExternalFormContextProviderProps {
/** List of FormTypeInputDefinition declared externally */
formTypeInputDefinitions?: FormTypeInputDefinition[];
/** FormGroupRenderer component declared externally */
FormGroupRenderer?: ComponentType<FormTypeRendererProps>;
/** FormLabelRenderer component declared externally */
FormLabelRenderer?: ComponentType<FormTypeRendererProps>;
/** FormInputRenderer component declared externally */
FormInputRenderer?: ComponentType<FormTypeRendererProps>;
/** FormErrorRenderer component declared externally */
FormErrorRenderer?: ComponentType<FormTypeRendererProps>;
/** FormatError function declared externally */
formatError?: FormatError;
/**
* Error display condition
* - `true`: Always show errors
* - `false`: Never show errors
* - `ShowError.Dirty`: Show errors when value has changed
* - `ShowError.Touched`: Show errors when input has been focused
* - `ShowError.DirtyTouched`: Show errors when both Dirty and Touched states are met
*/
showError?: boolean | ShowError;
/**
* Execute Validation Mode
* - `ValidationMode.None`: Disable validation
* - `ValidationMode.OnChange`: Validate when value changes
* - `ValidationMode.OnRequest`: Validate on request
*/
validationMode?: ValidationMode;
/** ValidatorFactory declared externally, creates internally if not provided */
validatorFactory?: ValidatorFactory;
/** Global user-defined context, merged with user-defined context */
context?: Dictionary;
}
/**
* Provides external form configuration through React context.
*
* Wraps child components with form-level configuration that applies to all nested forms.
* This allows centralized configuration of form behavior, custom components, and validation
* without prop drilling. Useful for applying consistent styling and behavior across
* multiple forms in an application.
*
* @example
* Basic usage with custom renderers:
* ```tsx
* function App() {
* return (
* <FormProvider
* FormLabelRenderer={CustomLabel}
* FormErrorRenderer={CustomError}
* showError={ShowError.Touched}
* >
* <MyForms />
* </FormProvider>
* );
* }
* ```
*
* @example
* Custom form type definitions:
* ```tsx
* const customFormTypes = [
* {
* test: { type: 'string', format: 'phone' },
* Component: PhoneInput,
* },
* {
* test: { type: 'string', format: 'ssn' },
* Component: SSNInput,
* },
* ];
*
* <FormProvider
* formTypeInputDefinitions={customFormTypes}
* >
* <Form jsonSchema={schema} />
* </FormProvider>
* ```
*
* @example
* Global error formatting:
* ```tsx
* const formatError = (error, node, context) => {
* const fieldName = node.jsonSchema.title || node.name;
*
* switch (error.keyword) {
* case 'required':
* return `${fieldName} is required`;
* case 'minLength':
* return `${fieldName} must be at least ${error.details?.limit} characters`;
* case 'pattern':
* return `${fieldName} has invalid format`;
* default:
* return error.message || 'Invalid value';
* }
* };
*
* <FormProvider
* formatError={formatError}
* showError={true}
* >
* <MyForms />
* </FormProvider>
* ```
*
* @example
* Custom validation with external validator:
* ```tsx
* import Ajv from 'ajv';
* import addFormats from 'ajv-formats';
*
* const ajv = new Ajv({ allErrors: true });
* addFormats(ajv);
*
* const validatorFactory = (jsonSchema) => {
* const validate = ajv.compile(jsonSchema);
* return (value) => {
* validate(value);
* return validate.errors?.map(err => ({
* dataPath: err.instancePath,
* keyword: err.keyword,
* message: err.message,
* details: err.params,
* source: err,
* })) || [];
* };
* };
*
* <FormProvider
* validatorFactory={validatorFactory}
* validationMode={ValidationMode.OnChange}
* >
* <Form jsonSchema={schema} />
* </FormProvider>
* ```
*
* @example
* Complete configuration example:
* ```tsx
* <FormProvider
* // Custom renderers
* FormGroupRenderer={MyFormGroup}
* FormLabelRenderer={MyFormLabel}
* FormInputRenderer={MyFormInput}
* FormErrorRenderer={MyFormError}
*
* // Custom input types
* formTypeInputDefinitions={[
* { test: { format: 'date' }, Component: DatePicker },
* { test: { format: 'time' }, Component: TimePicker },
* ]}
*
* // Error handling
* formatError={customFormatError}
* showError={ShowError.DirtyTouched}
*
* // Validation
* validationMode={ValidationMode.OnChange}
* validatorFactory={customValidator}
*
* // Global context
* context={{
* theme: 'dark',
* locale: 'en-US',
* apiEndpoint: '/api/v1',
* }}
* >
* <ApplicationForms />
* </FormProvider>
* ```
*
* @remarks
* - Configuration from this provider is merged with form-level props
* - Form-level props take precedence over provider configuration
* - Use `registerPlugin` for truly global configuration across the entire app
* - This provider is ideal for section-specific or feature-specific configuration
*/
export declare const ExternalFormContextProvider: ({ formTypeInputDefinitions, FormGroupRenderer, FormLabelRenderer, FormInputRenderer, FormErrorRenderer, formatError, showError, validationMode, context: inputContext, validatorFactory, children, }: PropsWithChildren<ExternalFormContextProviderProps>) => import("react/jsx-runtime").JSX.Element;