Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 49 additions & 71 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/common/src/wizard/enter-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AnyObject } from '@data-driven-forms/react-form-renderer';

interface FormOptions {
valid: boolean;
getState: () => AnyObject & { validating: boolean; values: AnyObject };
getState: () => AnyObject & { validating?: boolean; values: AnyObject };
getRegisteredFields: () => AnyObject;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { FieldMetaState } from 'react-final-form';

export interface ExtendedFieldMeta extends FieldMetaState<any>, Record<string, unknown> {
export interface ExtendedFieldMeta extends Record<string, unknown> {
error?: string;
submitError?: string;
touched?: boolean;
warning?: any;
}

export const validationError = (meta: ExtendedFieldMeta, validateOnMount?: boolean): string | undefined => {
export const validationError = (meta: ExtendedFieldMeta, validateOnMount?: boolean): string | false | undefined => {
if (validateOnMount) {
return meta.error || meta.submitError;
}

return meta.touched && (meta.error || meta.submitError);
return meta.touched ? meta.error || meta.submitError : false;
};

export default validationError;
6 changes: 3 additions & 3 deletions packages/mui-component-mapper/src/wizard/step-buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ const StyledGrid = styled(Grid)(() => ({

interface FormState {
values: AnyObject;
valid: boolean;
validating: boolean;
submitting: boolean;
valid?: boolean;
validating?: boolean;
submitting?: boolean;
}

interface NextButtonProps {
Expand Down
9 changes: 4 additions & 5 deletions packages/react-form-renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@
"process": "^0.11.10"
},
"dependencies": {
"final-form": "^4.20.10",
"final-form-arrays": "^3.0.2",
"final-form-focus": "^1.1.2",
"final-form": "^5.0.1",
"final-form-arrays": "^4.0.1",
"lodash": "^4.18.1",
"react-final-form": "^6.5.0",
"react-final-form-arrays": "^3.1.1"
"react-final-form": "^7.0.1",
"react-final-form-arrays": "^5.0.0"
},
"peerDependencies": {
"react": "^17.0.2 || ^18.0.0 || ^19.0.0",
Expand Down
62 changes: 62 additions & 0 deletions packages/react-form-renderer/src/form-renderer/focus-decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { FormApi, getIn } from 'final-form';

type FocusableInput = { name: string; focus: () => void };
type GetInputs = () => FocusableInput[];
type FindInput = (inputs: FocusableInput[], errors: Record<string, any>) => FocusableInput | undefined;

const isFocusableInput = (el: any): boolean => !!(el && typeof el.focus === 'function');

const defaultGetInputs: GetInputs = () => {
if (typeof document === 'undefined') return [];
return Array.prototype.slice
.call(document.forms)
.reduce((acc: FocusableInput[], form: HTMLFormElement) => {
return acc.concat(Array.prototype.slice.call(form).filter(isFocusableInput));
}, []);
};

const defaultFindInput: FindInput = (inputs, errors) =>
inputs.find((input) => input.name && getIn(errors, input.name));

const createFocusDecorator = (getInputs?: GetInputs, findInputFn?: FindInput) => {
return (form: FormApi) => {
const focusOnFirstError = (errors: Record<string, any>) => {
const inputs = (getInputs || defaultGetInputs)();
const firstInput = (findInputFn || defaultFindInput)(inputs, errors);
if (firstInput) firstInput.focus();
};

const originalSubmit = form.submit;
let state: { errors?: Record<string, any>; submitErrors?: Record<string, any> } = {};

const unsubscribe = form.subscribe(
(nextState) => { state = nextState; },
{ errors: true, submitErrors: true }
);

const afterSubmit = () => {
if (state.errors && Object.keys(state.errors).length) {
focusOnFirstError(state.errors);
} else if (state.submitErrors && Object.keys(state.submitErrors).length) {
focusOnFirstError(state.submitErrors);
}
};

form.submit = () => {
const result = originalSubmit.call(form);
if (result && typeof result.then === 'function') {
result.then(afterSubmit, () => {});
} else {
afterSubmit();
}
return result;
};

return () => {
unsubscribe();
form.submit = originalSubmit;
};
};
};

export default createFocusDecorator;
16 changes: 8 additions & 8 deletions packages/react-form-renderer/src/form-renderer/form-renderer.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import arrayMutators from 'final-form-arrays';
import createFocusDecorator from 'final-form-focus';
import createFocusDecorator from './focus-decorator';
import React, { useCallback, useMemo, useRef, useState, cloneElement, ReactNode, ComponentType, FunctionComponent, ReactElement } from 'react';
import { FormProps } from 'react-final-form';
import { FormApi } from 'final-form';

import defaultSchemaValidator from '../default-schema-validator';
import defaultValidatorMapper from '../validator-mapper';
import Form from '../form';
import RendererContext from '../renderer-context';
import RendererContext, { FormOptions } from '../renderer-context';
import renderForm from './render-form';
import SchemaErrorComponent from './schema-error-component';
import Schema from '../common-types/schema';
Expand All @@ -21,14 +21,14 @@ import { ConditionMapper } from './condition-mapper';

export interface FormRendererProps<
FormValues = Record<string, any>,
InitialFormValues = Partial<FormValues>,
InitialFormValues extends Partial<FormValues> = Partial<FormValues>,
FormTemplateProps extends FormTemplateRenderProps = FormTemplateRenderProps
> extends Omit<NoIndex<FormProps<FormValues, InitialFormValues>>, 'onSubmit' | 'children'> {
> extends Omit<NoIndex<FormProps<FormValues>>, 'onSubmit' | 'children'> {
initialValues?: InitialFormValues;
onCancel?: (values: FormValues, ...args: any[]) => void;
onReset?: () => void;
onError?: (...args: any[]) => void;
onSubmit?: FormProps<FormValues, InitialFormValues>['onSubmit'];
onSubmit?: FormProps<FormValues>['onSubmit'];
schema: Schema | (Record<string, any> & { fields: Array<Record<string, any>> });
clearOnUnmount?: boolean;
clearedValue?: any;
Expand Down Expand Up @@ -82,7 +82,7 @@ const renderChildren = (children: ReactNode | ((props: Record<string, any>) => R

function FormRenderer<
FormValues = Record<string, any>,
InitialFormValues = Partial<FormValues>,
InitialFormValues extends Partial<FormValues> = Partial<FormValues>,
FTP extends FormTemplateRenderProps = FormTemplateRenderProps
>({
actionMapper,
Expand Down Expand Up @@ -214,7 +214,7 @@ function FormRenderer<
onCancel: isFunc(onCancel) ? handleCancelCallback(getState) : undefined,
onReset: handleResetCallback(reset),
onError: handleErrorCallback,
getState,
getState: getState as FormOptions['getState'],
valid,
clearedValue,
submit,
Expand All @@ -240,7 +240,7 @@ function FormRenderer<
</RendererContext.Provider>
)}
{...props}
initialValues={initialValues}
initialValues={initialValues as Partial<FormValues>}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Field from '../common-types/field';
import Schema from '../common-types/schema';
import { ConditionMapper } from '../form-renderer/condition-mapper';

export interface FormOptions<FormValues = Record<string, any>, InitialFormValues = Partial<FormValues>>
export interface FormOptions<FormValues = Record<string, any>, InitialFormValues extends Partial<FormValues> = Partial<FormValues>>
extends FormApi<FormValues, InitialFormValues> {
registerInputFile?: (name: keyof FormValues) => void;
unRegisterInputFile?: (name: keyof FormValues) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface UseFieldApiConfig extends AnyObject {
type?: string;
}

export interface UseFieldApiComponentConfig extends UseFieldConfig<any> {
export interface UseFieldApiComponentConfig extends UseFieldConfig {
name: string;
}

Expand Down
Loading