UNPKG

finform-react-builder

Version:

A powerful, flexible React form builder with dynamic field rendering, custom validation, multi-step forms, Material-UI integration, image component support, toggle/radio buttons, switches, autocomplete, and advanced button positioning

429 lines (428 loc) 12.5 kB
export interface ValidationRule { pattern?: string | RegExp; message?: string; required?: boolean | ((formValues?: any) => boolean); minLength?: number; maxLength?: number; min?: number | string | { field: string; message?: string; }; max?: number | string | { field: string; message?: string; }; custom?: (value: any, formValues?: any) => boolean | string; } export interface ApiConfig { endpoint: string; method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; valueField?: string; labelField?: string; headers?: Record<string, string>; params?: Record<string, any>; body?: any; transform?: (data: any[]) => Array<{ label: string; value: string | number; }>; dependsOn?: string; conditional?: boolean; passThroughFields?: string[]; } export interface BaseField { id?: string; title?: string; name: string; label: string; type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'select' | 'checkbox' | 'checkboxGroup' | 'toggle' | 'radio' | 'switch' | 'autocomplete' | 'date' | 'textarea' | 'image' | 'title' | 'section' | 'component' | 'finuiHeader' | 'tabs' | 'grid' | 'listcards' | 'dragdroplist'; placeholder?: string; labelPosition?: 'inner' | 'top' | 'none'; labelVariant?: 'caption' | 'body2' | 'subtitle2' | 'h6'; required?: boolean | ((formValues?: any) => boolean); disabled?: boolean; copyWhenDisabled?: boolean; passThroughFields?: string[]; helperText?: string; validation?: ValidationRule; step?: number; value?: any | ((form: any) => any); valueDeps?: string[]; col?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; xs?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; sm?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; md?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; lg?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; xl?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; api_endpoint?: string; api_method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; value_field?: string; label_field?: string; depends_on?: string; conditional?: boolean; apiConfig?: ApiConfig; showWhen?: ((formData: any) => boolean) | { field: string; equals: any; } | { field: string; in: any[]; }; } export interface TextField extends BaseField { type: 'text' | 'email' | 'password' | 'tel' | 'textarea'; minLength?: number; maxLength?: number; pattern?: string; } export interface NumberField extends BaseField { type: 'number'; min?: number; max?: number; } export interface SelectField extends BaseField { type: 'select'; options?: Array<{ label: string; value: string | number; }>; default?: string | number; api_endpoint?: string; api_method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; value_field?: string; label_field?: string; depends_on?: string; conditional?: boolean; apiConfig?: ApiConfig; } export interface CheckboxField extends BaseField { type: 'checkbox'; } export interface ToggleField extends BaseField { type: 'toggle'; options: Array<{ label: string; value: string | number; }>; } export interface RadioField extends BaseField { type: 'radio'; options: Array<{ label: string; value: string | number; description?: string; }>; row?: boolean; groupPadding?: number; itemGap?: number; helperText?: string; } export interface CheckboxGroupField extends BaseField { type: 'checkboxGroup'; options: Array<{ label: string; value: string | number; }>; row?: boolean | number; groupPadding?: number; itemGap?: number; helperText?: string; } export interface SwitchField extends BaseField { type: 'switch'; } export interface AutocompleteField extends BaseField { type: 'autocomplete'; options?: Array<{ label: string; value: string | number; }>; multiple?: boolean; freeSolo?: boolean; filterOptions?: boolean; selectedAssignments?: Record<string, string>; api_endpoint?: string; api_method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; value_field?: string; label_field?: string; depends_on?: string; conditional?: boolean; apiConfig?: ApiConfig; } export interface DateField extends BaseField { type: 'date'; minDate?: string; maxDate?: string; } export interface ImageField extends BaseField { type: 'image'; src?: string; alt?: string; width?: number | string; height?: number | string; style?: React.CSSProperties; className?: string; onClick?: () => void; defaultValue?: string; accept?: string | string[]; onFileSelected?: (file: File) => void; onRemove?: () => void; onPreview?: (url: string) => void; onSave?: (payload: { url: string; file?: File; }) => void; imagePlaceholder?: { icon?: 'upload' | 'image'; title?: string; subtitle?: string; buttonText?: string; helperText?: string; sx?: any; iconSx?: any; titleSx?: any; subtitleSx?: any; buttonSx?: any; helperTextSx?: any; }; imageUploaded?: { previewText?: string; removeText?: string; saveText?: string; showSave?: boolean; previewTitle?: string; replaceText?: string; closeText?: string; cardSx?: any; thumbnailSx?: any; fileNameSx?: any; fileMetaSx?: any; previewButtonSx?: any; removeButtonSx?: any; saveButtonSx?: any; }; } export interface ComponentField extends BaseField { type: 'component'; content?: React.ReactNode; render?: () => React.ReactNode; } export interface TitleField extends BaseField { type: 'title'; variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; color?: string; align?: 'left' | 'center' | 'right'; sx?: any; } export interface SectionField extends BaseField { type: 'section'; variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; color?: string; align?: 'left' | 'center' | 'right'; sx?: any; cardWrap?: boolean; cardSx?: any; cardProps?: any; } export interface FinUiHeaderField extends BaseField { type: 'finuiHeader'; title?: string; subtitle?: string; align?: 'left' | 'center' | 'right'; actions?: any; actionName?: string; actionComponent?: 'switch' | 'checkbox'; actionLabel?: string; cardWrap?: boolean; cardSx?: any; cardProps?: any; } export interface TabsField extends BaseField { type: 'tabs'; items: Array<{ label: React.ReactNode; value?: string | number | React.ReactNode; content?: React.ReactNode; disabled?: boolean; fields?: FieldConfig[]; }>; defaultValue?: any; tabSx?: any; } export interface GridField extends BaseField { type: 'grid'; initialRow: Record<string, any>; columns: Array<{ key: string; header: string; type?: 'text' | 'number' | 'select' | 'checkbox' | 'date' | 'index'; width?: number | string | 'auto'; options?: { label: string; value: any; }[]; placeholder?: string; disabled?: boolean | ((row: any, index: number) => boolean); value?: any | ((row: any, index: number) => any); editable?: boolean; indexFormat?: (index: number) => string; helperText?: string; required?: boolean; minLength?: number; maxLength?: number; pattern?: string; min?: number; max?: number; step?: number; endorsementText?: string | ((row: any, index: number) => string); endorsementBg?: string; endorsementColor?: string; endorsementRadius?: number | string; endorsementHeight?: number; endorsementPaddingX?: number; apiConfig?: { endpoint: string; method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; valueField?: string; labelField?: string; headers?: Record<string, string>; params?: Record<string, any>; body?: any; transform?: (data: any[]) => Array<{ label: string; value: string | number; }>; dependsOn?: string; conditional?: boolean; passThroughFields?: string[]; }; sx?: any; cellSx?: any; }>; addLabel?: string; rowDeletable?: boolean; addActions?: { label: string; template: Record<string, any>; }[]; emptyTitle?: string; emptySubtitle?: string; emptyCardSx?: any; } export interface ListCardsField extends BaseField { type: 'listcards'; items: Array<{ id: string | number; header?: string; chipText?: string; leftAction?: { name: string; label?: string; }; rightAction?: { name: string; label?: string; }; }>; sx?: any; cardSx?: any; } export interface DragDropListField extends Omit<BaseField, 'helperText'> { type: 'dragdroplist'; items: any[]; getId?: string | ((item: any) => string | number); getText?: string | ((item: any) => string); header?: React.ReactNode; chipText?: string | ((item: any, index: number) => string | undefined); showIndex?: boolean; showLeftIcon?: boolean; renderItem?: (item: any, isDragging: boolean) => React.ReactNode; helperText?: React.ReactNode | string; sx?: any; } export type FieldConfig = TextField | NumberField | SelectField | CheckboxField | CheckboxGroupField | ToggleField | RadioField | SwitchField | AutocompleteField | DateField | ImageField | TitleField | SectionField | ComponentField | FinUiHeaderField | TabsField | GridField | ListCardsField | DragDropListField; export interface FormButton { text: string; color?: string; size?: 'small' | 'medium' | 'large'; onClick?: () => void; disabled?: boolean; loading?: boolean; position?: 'left' | 'center' | 'right' | 'space-between'; type?: 'submit' | 'button' | 'reset'; sx?: any; } export interface ButtonGroup { buttons: FormButton[]; position?: 'left' | 'center' | 'right' | 'space-between'; layout?: 'horizontal' | 'vertical'; spacing?: number; sx?: any; } export interface FormTitle { text: string; variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; color?: string; align?: 'left' | 'center' | 'right'; sx?: any; } export interface FormTheme { primaryColor?: string; secondaryColor?: string; backgroundColor?: string; textColor?: string; borderRadius?: number | string; spacing?: number; typography?: { fontFamily?: string; fontSize?: number | string; }; } export interface FinFormProps { id?: string; title?: FormTitle; theme?: FormTheme; fields: FieldConfig[]; onSubmit: (data: any) => void; onChange?: (data: any) => void; submitButtonText?: string; onSubmitClick?: (data: any) => void; defaultValues?: Record<string, any>; showSubmitButton?: boolean; buttons?: FormButton[]; buttonGroup?: ButtonGroup; stickyButtons?: boolean; stickyButtonsSx?: any; fixedButtons?: boolean; fixedButtonsSx?: any; formCardWrap?: boolean; formCardSx?: any; formCardProps?: any; baseUrl?: string; apiHeaders?: Record<string, string>; isMultiStep?: boolean; currentStep?: number; onStepChange?: (currentStep: number, totalSteps: number) => void; showStepNavigation?: boolean; stepNavigationProps?: { showStepTitles?: boolean; stepTitles?: string[]; }; } export interface FieldRendererProps { field: FieldConfig; control: any; errors: any; baseUrl?: string; apiHeaders?: Record<string, string>; formData?: Record<string, any>; setValue?: (name: string, value: any, options?: any) => void; } export interface StepNavigationProps { currentStep: number; totalSteps: number; onStepChange: (step: number) => void; stepTitles?: string[]; showStepTitles?: boolean; completedSteps?: number[]; }