UNPKG

red-form

Version:

A powerful, type-safe React form library that lets you create dynamic dialog-based forms using schema definitions — inspired by Formik but designed for real-time UI rendering and reusability.

346 lines (300 loc) 9.68 kB
import * as react_jsx_runtime from 'react/jsx-runtime'; import { ReactNode, Dispatch, SetStateAction, CSSProperties } from 'react'; type ModalProps = { isOpen: boolean; onClose?: () => void; title?: string; children: React.ReactNode; width?: number; height?: number; minHeight?: number; }; type Adorment = { start: ReactNode | undefined; end: ReactNode | undefined; }; type Option = string | { label: string; value: string }; type InputProps<T extends Schema, K extends keyof T> = { field: string; props: T[K]; form: FormInstance<T>; error: string[] | undefined; sx: FormSX }; type BaseField = { label: string; required?: boolean; placeholder?: string; helperText?: ReactNode; information?: string; disabled?: boolean; span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; validate?: <T extends Schema, K extends keyof T>({ field, props, form }: { field: string; props: T[K]; form: FormInstance<T> }) => string[]; }; type TextFieldProps = BaseField & { component: "text"; value: string; autoFill?: AutoFillField; min?: number; max?: number; adorment?: Adorment; }; type EmailFieldProps = BaseField & { component: "email"; value: string; adorment?: Adorment; }; type SearchFieldProps = BaseField & { component: "search"; value: string; autoFill?: AutoFillField; adorment?: Adorment; }; type NumberFieldProps = BaseField & { component: "number"; value: number; min?: number; max?: number; step?: number; adorment?: Adorment; }; type PasswordFieldProps = BaseField & { component: "password"; value: string; min?: number; max?: number; adorment?: Adorment; }; type DateFieldProps = BaseField & { component: "date"; value: `${1 | 2}${number}${number}${number}-${0 | 1}${number}-${0 | 1 | 2 | 3}${number}` | ""; min?: string; max?: string; adorment?: Adorment; }; type DateTimeFieldProps = BaseField & { component: "datetime"; value: `${1 | 2}${number}${number}${number}-${0 | 1}${number}-${0 | 1 | 2 | 3}${number}T${0 | 1 | 2}${number}:${0 | 1 | 2 | 3 | 4 | 5 | 6}${number}` | ""; min?: string; max?: string; adorment?: Adorment; }; type TimeFieldProps = BaseField & { component: "time"; value: `${0 | 1 | 2}${number}:${0 | 1 | 2 | 3 | 4 | 5 | 6}${number}` | ""; min?: string; max?: string; adorment?: Adorment; }; type WeekFieldProps = BaseField & { component: "week"; value: `${number}${number}${number}${number}-W${number}${number}` | ""; min?: number; max?: number; adorment?: Adorment; }; type MonthFieldProps = BaseField & { component: "month"; value: `${1 | 2}${number}${number}${number}-${0 | 1}${number}` | ""; min?: number; max?: number; adorment?: Adorment; }; type TelephoneFieldProps = BaseField & { component: "telephone"; value: number; min?: number; max?: number; adorment?: Adorment; }; type TextAreaFieldProps = BaseField & { component: "textarea"; value: string; min?: number; max?: number; }; type CheckboxFieldProps = BaseField & { component: "checkbox"; value: string[] | string | undefined; direction?: "row" | "column"; options: (string | { label: string; value: string })[]; }; type RadioFieldProps = BaseField & { component: "radio"; value: string; direction?: "row" | "column"; options: Option[]; }; type RangeFieldProps = BaseField & { component: "range"; value: number; min: number; max: number; step?: number; }; type ColorFieldProps = BaseField & { component: "color"; value: `#${string}`; }; type SwitchFieldProps = BaseField & { component: "switch"; value: boolean; }; type SelectFieldProps = BaseField & { component: "select"; value: string; options: Option[]; }; type MultiSelectFieldProps = BaseField & { component: "multi-select"; value: string[]; options: Option[]; }; type TagsFieldProps = BaseField & { component: "tags"; value: string[]; }; type ImageFieldProps = BaseField & { component: "image"; value: string; onSelect: (file: File) => Promise<string>; }; type CustomFieldProps = BaseField & { component: "custom"; value?: ReactNode; inputBase?: boolean; render: <T extends Schema, K extends keyof T>({ field, props, form }: InputProps<T, K>) => ReactNode; }; type FieldSchema = | TextFieldProps | EmailFieldProps | SearchFieldProps | PasswordFieldProps | NumberFieldProps | DateFieldProps | DateTimeFieldProps | TimeFieldProps | WeekFieldProps | MonthFieldProps | TimeFieldProps | TelephoneFieldProps | TextAreaFieldProps | CheckboxFieldProps | RadioFieldProps | SwitchFieldProps | RangeFieldProps | ColorFieldProps | SelectFieldProps | MultiSelectFieldProps | TagsFieldProps | ImageFieldProps | CustomFieldProps; type Schema = Record<string, FieldSchema>; // type Values<T extends Schema> = { // [K in keyof T]: T[K]["type"] extends "number" // ? T[K]["required"] extends true // ? number // : number | undefined // : T[K]["type"] extends "text" // ? T[K]["required"] extends true // ? string // : string | undefined // : unknown; // }; type Values<T extends Schema> = { [K in keyof T]: T[K]["required"] extends true ? T[K]["value"] : T[K]["value"] | undefined; }; type ValidateOnType = ("submit" | "change")[]; type FormSX = { conteiner?: CSSProperties; title?: CSSProperties; description?: CSSProperties; form?: CSSProperties; actionArea?: CSSProperties; resetButton?: CSSProperties; submitButton?: CSSProperties; inputContainer?: CSSProperties; inputLabelContainer?: CSSProperties; inputLabel?: CSSProperties; tooltipContainer?: CSSProperties; tooltipInfoIcon?: CSSProperties; tooltip?: CSSProperties; errorList?: CSSProperties; errorItem?: CSSProperties; helperText?: CSSProperties; inputBase?: CSSProperties; }; type FormProps<T extends Schema> = { // FORM FIELDS title?: string | ReactNode; description?: ReactNode; options?: { validateOn?: FormOptions["validateOn"]; }; sx?: FormSX; onSubmit?: (values: Values<T>) => void | Promise<void>; onChange?: (values: Values<T>) => void; onError?: (values: Errors<T>) => void; onBlur?: (values: Touched<T>) => void; disabled?: boolean; schema: T; // DIALOG FIELDS open?: boolean; close?: boolean; width?: number; height?: number; minHeight?: number; onClose: () => void; }; type Errors<T extends Schema> = Partial<Record<keyof T, string[] | undefined>>; type Touched<T extends Schema> = Partial<Record<keyof T, boolean>>; type FormOptions = { validateOn?: ValidateOnType; }; interface FormInstance<T extends Schema> { submitting: boolean; setSubmitting: React.Dispatch<React.SetStateAction<boolean>>; values: Values<T>; setFieldValue: <K extends keyof T>(field: K, value: Values<T>[K]) => void; setValues: React.Dispatch<React.SetStateAction<Values<T>>>; errors: Errors<T>; setFieldError: <K extends keyof T>(field: K, message: string) => void; setErrors: Dispatch<SetStateAction<Partial<Record<keyof T, string[]>>>>; touched: Touched<T>; setFieldTouched: <K extends keyof T>(field: K, value: boolean) => void; setTouched: Dispatch<SetStateAction<Partial<Record<keyof T, boolean>>>>; handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void; activeField: string | undefined; setFieldActive: <K extends keyof T>(field: K | undefined) => void; handleFocus: (e: React.FocusEvent<HTMLInputElement>) => void; handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void; handleSubmit: (e: React.FormEvent) => void; validate: () => boolean; resetForm: () => void; submit: () => void; // handleChange: <K extends keyof T>(field: K, value: Values<T>[K]) => void; // handleBlur: <K extends keyof T>(field: K) => void; getFieldProps: <K extends keyof T>( field: K ) => { name: K; // value: Values<T>[K]; value: T[K]["value"] | undefined | any; id: K; required: boolean; disabled: boolean; ref: React.RefObject<HTMLInputElement | null> | undefined; placeholder: string | undefined; onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void; autoComplete: AutoFill | undefined; onBlur: (e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void; onFocus: (e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void; onMouseDown: (e: React.MouseEvent<HTMLInputElement | HTMLTextAreaElement>) => void; }; } declare function useForm<T extends Schema>(schema: T, onSubmit: (values: Values<T>) => void, options?: FormOptions): FormInstance<T>; declare const Form: <T extends Schema>({ schema, title, description, disabled, onSubmit, onChange, onError, onBlur, sx, options }: Omit<FormProps<T>, "open" | "close" | "minHeight" | "width" | "height" | "onClose">) => react_jsx_runtime.JSX.Element; declare const FormProvider: ({ children }: { children: ReactNode; }) => react_jsx_runtime.JSX.Element; declare const useModalForm: <T extends Schema>(schema: T, options: Omit<FormProps<T>, "schema" | "onClose">) => { open: () => void; close: () => void; }; declare const Modal: (props: ModalProps) => react_jsx_runtime.JSX.Element | null; declare const create: <T extends Schema>(schema: T) => T; export { FormProvider, Modal, type Schema, create, Form as default, useForm, useModalForm };