Skip to content

Commit

Permalink
[@mantine/form] Add form.initialize
Browse files Browse the repository at this point in the history
  • Loading branch information
rtivital committed Dec 16, 2023
1 parent 859d432 commit 6472986
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
48 changes: 47 additions & 1 deletion packages/@mantine/form/src/stories/Form.usage.story.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Checkbox, NativeSelect, Textarea, TextInput } from '@mantine/core';
import { Button, Checkbox, NativeSelect, Textarea, TextInput } from '@mantine/core';
import { useForm } from '../use-form';
import { FormBase } from './_base';

Expand Down Expand Up @@ -30,3 +30,49 @@ export function Usage() {
</FormBase>
);
}

interface FormValues {
name: string;
terms: boolean;
area: string;
select: string;
}

export function Initialize() {
const form = useForm<FormValues>({
initialValues: { name: '', terms: false, area: '', select: '' },
validate: {
name: (value) => (value.length === 0 ? 'Required' : null),
},
});

return (
<FormBase form={form}>
<TextInput label="Name" {...form.getInputProps('name')} />
<Checkbox
mt="md"
label="Accept terms of use"
{...form.getInputProps('terms', { type: 'checkbox' })}
/>
<Textarea label="area" {...form.getInputProps('area')} />
<NativeSelect
label="native select"
data={['React', 'Angular']}
{...form.getInputProps('select')}
/>

<Button
onClick={() =>
form.initialize({
name: 'Mantine',
terms: true,
area: 'Some area',
select: 'React',
})
}
>
Initialize
</Button>
</FormBase>
);
}
17 changes: 17 additions & 0 deletions packages/@mantine/form/src/tests/initialize.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { act, renderHook } from '@testing-library/react';
import { useForm } from '../use-form';

describe('@mantine/form/initialize', () => {
it('initializes form with given values with form.initialize', () => {
const hook = renderHook(() => useForm({ initialValues: { a: 1, b: 2 } }));
expect(hook.result.current.values).toStrictEqual({ a: 1, b: 2 });

act(() => hook.result.current.initialize({ a: 3, b: 4 }));
expect(hook.result.current.values).toStrictEqual({ a: 3, b: 4 });
expect(hook.result.current.initialized).toBe(true);

act(() => hook.result.current.setValues({ a: 1, b: 2 }));
act(() => hook.result.current.initialize({ a: 5, b: 6 }));
expect(hook.result.current.values).toStrictEqual({ a: 1, b: 2 });
});
});
3 changes: 3 additions & 0 deletions packages/@mantine/form/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export type ResetStatus = () => void;

export type ResetDirty<Values> = (values?: Values) => void;
export type IsValid<Values> = <Field extends LooseKeys<Values>>(path?: Field) => boolean;
export type Initialize<Values> = (values: Values) => void;

export type _TransformValues<Values> = (values: Values) => unknown;

Expand All @@ -134,7 +135,9 @@ export interface UseFormReturnType<
TransformValues extends _TransformValues<Values> = (values: Values) => Values,
> {
values: Values;
initialized: boolean;
errors: FormErrors;
initialize: Initialize<Values>;
setValues: SetValues<Values>;
setInitialValues: SetInitialValues<Values>;
setErrors: SetErrors;
Expand Down
22 changes: 18 additions & 4 deletions packages/@mantine/form/src/use-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
GetFieldStatus,
GetInputProps,
GetTransformedValues,
Initialize,
InsertListItem,
IsValid,
OnReset,
Expand All @@ -38,7 +39,7 @@ export function useForm<
TransformValues extends _TransformValues<Values> = (values: Values) => Values,
>({
name,
initialValues = {} as Values,
initialValues,
initialErrors = {},
initialDirty = {},
initialTouched = {},
Expand All @@ -51,18 +52,29 @@ export function useForm<
}: UseFormInput<Values, TransformValues> = {}): UseFormReturnType<Values, TransformValues> {
const [touched, setTouched] = useState(initialTouched);
const [dirty, setDirty] = useState(initialDirty);
const [values, _setValues] = useState(initialValues);
const [values, _setValues] = useState((initialValues || {}) as Values);
const [errors, _setErrors] = useState(filterErrors(initialErrors));
const [initialized, setInitialized] = useState(false);

const valuesSnapshot = useRef<Values>(initialValues);
const valuesSnapshot = useRef<Values>((initialValues || {}) as Values);
const setValuesSnapshot = (_values: Values) => {
valuesSnapshot.current = _values;
};

const initialize: Initialize<Values> = useCallback(
(_values) => {
if (!initialized) {
setInitialized(true);
_setValues(_values);
}
},
[initialized]
);

const resetTouched = useCallback(() => setTouched({}), []);
const resetDirty: ResetDirty<Values> = (_values) => {
const newSnapshot = _values ? { ...values, ..._values } : values;
setValuesSnapshot(newSnapshot);
setValuesSnapshot(newSnapshot as Values);
setDirty({});
};

Expand Down Expand Up @@ -277,8 +289,10 @@ export function useForm<
);

const form: UseFormReturnType<Values, TransformValues> = {
initialized,
values,
errors,
initialize,
setValues,
setInitialValues: setValuesSnapshot,
setErrors,
Expand Down

0 comments on commit 6472986

Please sign in to comment.