@ultraviolet/form 2.0.0-next.7 → 2.0.0-next.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,12 @@
1
1
  import { Checkbox } from '@ultraviolet/ui';
2
- import { forwardRef } from 'react';
2
+ import { useController } from 'react-hook-form';
3
3
  import { jsx } from '@emotion/react/jsx-runtime';
4
4
  import { useErrors } from '../../providers/ErrorContext/index.js';
5
- import { useFormField } from '../../hooks/useFormField.js';
6
5
 
7
- const CheckboxField = /*#__PURE__*/forwardRef((_ref, ref) => {
6
+ const CheckboxField = _ref => {
8
7
  let {
9
- validate,
10
8
  name,
11
- label = '',
9
+ label,
12
10
  size,
13
11
  progress,
14
12
  disabled,
@@ -18,58 +16,57 @@ const CheckboxField = /*#__PURE__*/forwardRef((_ref, ref) => {
18
16
  onChange,
19
17
  onBlur,
20
18
  onFocus,
21
- value,
19
+ rules,
22
20
  helper,
23
21
  tooltip,
24
- 'data-testid': dataTestId
22
+ 'data-testid': dataTestId,
23
+ value,
24
+ shouldUnregister = false
25
25
  } = _ref;
26
26
  const {
27
27
  getError
28
28
  } = useErrors();
29
29
  const {
30
- input,
31
- meta
32
- } = useFormField(name, {
33
- disabled,
34
- required,
35
- type: 'checkbox',
36
- validate,
37
- value
38
- });
39
- const error = getError({
40
- label,
41
- meta: meta,
30
+ field,
31
+ fieldState: {
32
+ error
33
+ }
34
+ } = useController({
42
35
  name,
43
- value: input.value ?? input.checked
36
+ disabled,
37
+ shouldUnregister,
38
+ rules: {
39
+ required,
40
+ ...rules
41
+ }
44
42
  });
45
43
  return jsx(Checkbox, {
46
- name: input.name,
44
+ name: field.name,
47
45
  onChange: event => {
48
- input.onChange(event);
49
- onChange?.(event);
46
+ field.onChange(value ? [...(field.value ?? []), value] : event.target.checked);
47
+ onChange?.(event.target.checked);
50
48
  },
51
49
  onBlur: event => {
52
- input.onBlur(event);
50
+ field.onBlur();
53
51
  onBlur?.(event);
54
52
  },
55
- onFocus: event => {
56
- input.onFocus(event);
57
- onFocus?.(event);
58
- },
53
+ onFocus: onFocus,
59
54
  size: size,
60
55
  progress: progress,
61
- disabled: disabled,
62
- checked: input.checked,
63
- error: error,
64
- helper: helper,
65
- ref: ref,
56
+ disabled: field.disabled,
57
+ checked: Array.isArray(field.value) ? field.value.includes(value) : !!field.value,
58
+ error: getError({
59
+ label: label ?? ''
60
+ }, error),
61
+ ref: field.ref,
66
62
  className: className,
67
- value: input.value,
68
63
  required: required,
69
64
  "data-testid": dataTestId,
65
+ helper: helper,
70
66
  tooltip: tooltip,
67
+ value: value,
71
68
  children: children
72
69
  });
73
- });
70
+ };
74
71
 
75
72
  export { CheckboxField };
@@ -1,51 +1,50 @@
1
1
  import { CheckboxGroup } from '@ultraviolet/ui';
2
- import { useFieldArray } from 'react-final-form-arrays';
2
+ import { useController } from 'react-hook-form';
3
3
  import { jsx } from '@emotion/react/jsx-runtime';
4
4
  import { useErrors } from '../../providers/ErrorContext/index.js';
5
5
 
6
6
  const CheckboxGroupField = _ref => {
7
7
  let {
8
8
  legend,
9
- value,
10
9
  className,
11
10
  helper,
12
11
  direction,
13
12
  children,
14
13
  onChange,
14
+ label = '',
15
15
  error: customError,
16
16
  name,
17
- required = false
17
+ required = false,
18
+ shouldUnregister = false
18
19
  } = _ref;
19
20
  const {
20
21
  getError
21
22
  } = useErrors();
22
23
  const {
23
- fields,
24
- meta
25
- } = useFieldArray(name, {
26
- type: 'checkbox',
27
- value,
28
- validate: localValue => required && localValue?.length === 0 ? 'Required' : undefined
29
- });
30
- const error = getError({
31
- label: legend,
32
- meta,
33
- value: fields.value,
34
- name
24
+ field,
25
+ fieldState: {
26
+ error
27
+ }
28
+ } = useController({
29
+ name,
30
+ shouldUnregister
35
31
  });
36
32
  return jsx(CheckboxGroup, {
37
33
  legend: legend,
38
- name: fields.name,
39
- value: fields.value,
34
+ name: name,
35
+ value: field.value,
40
36
  onChange: event => {
41
- if (fields.value?.includes(event.currentTarget.value)) {
42
- fields.remove(fields.value.indexOf(event.currentTarget?.value));
37
+ const fieldValue = field.value;
38
+ if (fieldValue?.includes(event.currentTarget.value)) {
39
+ field.onChange(fieldValue?.filter(currentValue => currentValue !== event.currentTarget.value));
43
40
  } else {
44
- fields.push(event.currentTarget.value);
41
+ field.onChange([...field.value, event.currentTarget.value]);
45
42
  }
46
- onChange?.(event);
43
+ onChange?.(event.currentTarget.value);
47
44
  },
48
- error: error ?? customError,
45
+ error: getError({
46
+ label
47
+ }, error) ?? customError,
49
48
  className: className,
50
49
  direction: direction,
51
50
  helper: helper,
@@ -1,7 +1,9 @@
1
1
  import { DateInput } from '@ultraviolet/ui';
2
+ import { useController } from 'react-hook-form';
3
+ import { maxDateValidator } from '../../validators/maxDate.js';
4
+ import { minDateValidator } from '../../validators/minDate.js';
2
5
  import { jsx } from '@emotion/react/jsx-runtime';
3
6
  import { useErrors } from '../../providers/ErrorContext/index.js';
4
- import { useFormField } from '../../hooks/useFormField.js';
5
7
 
6
8
  const parseDate = value => typeof value === 'string' ? new Date(value) : value;
7
9
  const isEmpty = value => typeof value === 'string' ? value === '' : value === undefined;
@@ -10,87 +12,83 @@ const DateField = _ref => {
10
12
  required,
11
13
  name,
12
14
  label = '',
13
- validate,
14
15
  format,
15
16
  locale,
16
17
  maxDate,
17
18
  minDate,
18
- initialValue,
19
19
  disabled,
20
- value: inputVal,
21
20
  onChange,
22
21
  onBlur,
23
22
  onFocus,
24
- formatOnBlur,
23
+ rules,
25
24
  autoFocus = false,
26
25
  excludeDates,
27
26
  selectsRange,
28
- 'data-testid': dataTestId
27
+ 'data-testid': dataTestId,
28
+ shouldUnregister = false
29
29
  } = _ref;
30
30
  const {
31
31
  getError
32
32
  } = useErrors();
33
33
  const {
34
- input,
35
- meta
36
- } = useFormField(name, {
37
- disabled,
38
- formatOnBlur,
39
- initialValue,
40
- maxDate,
41
- minDate,
42
- required,
43
- validate,
44
- value: inputVal
45
- });
46
- const error = getError({
47
- label,
48
- maxDate,
49
- meta: meta,
50
- minDate,
34
+ field,
35
+ fieldState: {
36
+ error
37
+ }
38
+ } = useController({
51
39
  name,
52
- value: input.value
40
+ shouldUnregister,
41
+ rules: {
42
+ ...rules,
43
+ validate: {
44
+ ...rules?.validate,
45
+ minDate: minDateValidator(minDate),
46
+ maxDate: maxDateValidator(maxDate)
47
+ },
48
+ required
49
+ }
53
50
  });
54
51
  return jsx(DateInput, {
52
+ name: field.name,
55
53
  label: label,
54
+ value: field.value,
56
55
  format: format || (value => value ? parseDate(value).toLocaleDateString() : ''),
57
56
  locale: locale,
58
57
  required: required,
59
- value: input.value,
60
58
  onChange: val => {
61
59
  if (val && val instanceof Date) {
62
60
  onChange?.(val);
63
61
  const newDate = parseDate(val);
64
- if (isEmpty(input.value)) {
65
- input.onChange(newDate);
62
+ if (isEmpty(field.value)) {
63
+ field.onChange(newDate);
66
64
  return;
67
65
  }
68
- const currentDate = parseDate(input.value);
66
+ const currentDate = parseDate(field.value);
69
67
  newDate.setHours(currentDate.getHours(), currentDate.getMinutes());
70
- input.onChange(newDate);
68
+ field.onChange(newDate);
71
69
  } else if (Array.isArray(val)) {
72
- input.onChange(val);
70
+ field.onChange(val);
73
71
  }
74
72
  },
75
73
  onBlur: e => {
76
- input.onBlur(e);
74
+ field.onBlur();
77
75
  onBlur?.(e);
78
76
  },
79
- onFocus: e => {
80
- input.onFocus(e);
81
- onFocus?.(e);
82
- },
77
+ onFocus: onFocus,
83
78
  maxDate: maxDate,
84
79
  minDate: minDate,
85
- startDate: selectsRange ? input.value[0] : undefined,
86
- endDate: selectsRange ? input.value[1] : undefined,
87
- error: error,
80
+ error: getError({
81
+ minDate,
82
+ maxDate,
83
+ label
84
+ }, error),
88
85
  disabled: disabled,
89
86
  autoFocus: autoFocus,
90
- name: input.name,
91
- "data-testid": dataTestId,
92
87
  excludeDates: excludeDates,
93
- selectsRange: selectsRange
88
+ selectsRange: selectsRange,
89
+ "data-testid": dataTestId,
90
+ startDate: selectsRange && Array.isArray(field.value) ? field.value[0] : undefined,
91
+ endDate: selectsRange && Array.isArray(field.value) ? field.value[1] : undefined
94
92
  });
95
93
  };
96
94
 
@@ -1,43 +1,83 @@
1
- import arrayMutators from 'final-form-arrays';
2
- import { Form as Form$1 } from 'react-final-form';
1
+ import React, { useMemo } from 'react';
2
+ import { useForm, FormProvider } from 'react-hook-form';
3
+ import { FORM_ERROR } from '../../constants.js';
4
+ import { defaultErrors } from './defaultErrors.js';
3
5
  import { jsx } from '@emotion/react/jsx-runtime';
4
6
  import { ErrorProvider } from '../../providers/ErrorContext/index.js';
5
7
 
8
+ const FormSubmitContext = /*#__PURE__*/React.createContext({});
6
9
  const Form = _ref => {
7
10
  let {
8
11
  children,
9
- onRawSubmit,
10
- errors,
12
+ methods: methodsProp,
11
13
  initialValues,
12
- validateOnBlur,
13
- validate,
14
- name,
15
- render,
16
- mutators,
17
- keepDirtyOnReinitialize,
18
- className
14
+ errors,
15
+ onRawSubmit,
16
+ name
19
17
  } = _ref;
20
- return jsx(Form$1, {
21
- initialValues: initialValues,
22
- validateOnBlur: validateOnBlur,
23
- validate: validate,
24
- mutators: {
25
- ...arrayMutators,
26
- ...mutators
27
- },
28
- onSubmit: onRawSubmit,
29
- render: render ?? (renderProps => jsx(ErrorProvider, {
30
- errors: errors,
31
- children: jsx("form", {
32
- noValidate: true,
33
- name: name,
34
- onSubmit: renderProps.handleSubmit,
35
- className: className,
36
- children: typeof children === 'function' ? children(renderProps) : children
18
+ const methodsHook = useForm({
19
+ defaultValues: initialValues,
20
+ mode: 'onChange'
21
+ });
22
+ const methods = !methodsProp ? methodsHook : methodsProp;
23
+ const handleSubmit = methods.handleSubmit(async values => {
24
+ const result = await onRawSubmit(values, {
25
+ reset: methods.reset,
26
+ resetFieldState: methods.resetField,
27
+ restart: () => methods.reset(initialValues),
28
+ change: methods.setValue
29
+ });
30
+ if (result === null) {
31
+ methods.setError('root.submit', {
32
+ type: 'custom'
33
+ });
34
+ return;
35
+ }
36
+ if (result && typeof result !== 'boolean' && typeof result !== 'number') {
37
+ methods.setError('root.submit', {
38
+ type: 'custom',
39
+ message: typeof result === 'object' ? result[FORM_ERROR] : result
40
+ });
41
+ }
42
+ });
43
+ const formSubmitContextValue = useMemo(() => ({
44
+ handleSubmit
45
+ }), [handleSubmit]);
46
+ return jsx(FormProvider, {
47
+ ...methods,
48
+ children: jsx(FormSubmitContext.Provider, {
49
+ value: formSubmitContextValue,
50
+ children: jsx(ErrorProvider, {
51
+ errors: {
52
+ ...defaultErrors,
53
+ ...errors
54
+ },
55
+ children: jsx("form", {
56
+ onSubmit: async e => {
57
+ e.preventDefault();
58
+ e.stopPropagation();
59
+ await handleSubmit(e);
60
+ },
61
+ name: name,
62
+ children: typeof children === 'function' ? children({
63
+ values: methods.watch(),
64
+ hasValidationErrors: !methods.formState.isValid,
65
+ errors: methods.formState.errors,
66
+ submitting: methods.formState.isSubmitting,
67
+ pristine: !methods.formState.isDirty,
68
+ handleSubmit,
69
+ submitError: !!methods.formState.errors?.root?.['submit'],
70
+ valid: methods.formState.isValid,
71
+ form: {
72
+ change: methods.setValue,
73
+ reset: methods.reset,
74
+ submit: handleSubmit
75
+ }
76
+ }) : children
77
+ })
37
78
  })
38
- })),
39
- keepDirtyOnReinitialize: keepDirtyOnReinitialize
79
+ })
40
80
  });
41
81
  };
42
82
 
43
- export { Form };
83
+ export { Form, FormSubmitContext };
@@ -1,6 +1,7 @@
1
1
  import { NumberInput } from '@ultraviolet/ui';
2
+ import { useController } from 'react-hook-form';
2
3
  import { jsx } from '@emotion/react/jsx-runtime';
3
- import { useFormField } from '../../hooks/useFormField.js';
4
+ import { useErrors } from '../../providers/ErrorContext/index.js';
4
5
 
5
6
  const NumberInputField = _ref => {
6
7
  let {
@@ -17,38 +18,43 @@ const NumberInputField = _ref => {
17
18
  size,
18
19
  step,
19
20
  text,
20
- validate,
21
- value,
21
+ rules,
22
22
  className,
23
- 'data-testid': dataTestId
23
+ label,
24
+ shouldUnregister = false
24
25
  } = _ref;
25
26
  const {
26
- input
27
- } = useFormField(name, {
28
- disabled,
29
- required,
30
- type: 'number',
31
- validate,
32
- value,
33
- defaultValue: 0,
34
- max: maxValue,
35
- min: minValue
27
+ getError
28
+ } = useErrors();
29
+ const {
30
+ field,
31
+ fieldState: {
32
+ error
33
+ }
34
+ } = useController({
35
+ name,
36
+ shouldUnregister,
37
+ rules: {
38
+ max: maxValue,
39
+ min: minValue,
40
+ required,
41
+ ...rules
42
+ }
36
43
  });
37
44
  return jsx(NumberInput, {
38
- name: name,
45
+ name: field.name,
46
+ value: field.value,
39
47
  disabled: disabled,
40
48
  onBlur: event => {
41
- input.onBlur(event);
49
+ field.onBlur();
42
50
  onBlur?.(event);
43
51
  },
44
52
  onChange: event => {
45
- input.onChange(event);
53
+ // React hook form doesnt allow undefined values after definition https://react-hook-form.com/docs/usecontroller/controller (that make sense)
54
+ field.onChange(event ?? null);
46
55
  onChange?.(event);
47
56
  },
48
- onFocus: event => {
49
- input.onFocus(event);
50
- onFocus?.(event);
51
- },
57
+ onFocus: onFocus,
52
58
  maxValue: maxValue,
53
59
  minValue: minValue,
54
60
  onMinCrossed: onMinCrossed,
@@ -56,9 +62,13 @@ const NumberInputField = _ref => {
56
62
  size: size,
57
63
  step: step,
58
64
  text: text,
59
- value: input.value,
60
65
  className: className,
61
- "data-testid": dataTestId
66
+ label: label,
67
+ error: getError({
68
+ label: label ?? '',
69
+ max: maxValue,
70
+ min: minValue
71
+ }, error)
62
72
  });
63
73
  };
64
74
 
@@ -1,7 +1,7 @@
1
1
  import { Radio } from '@ultraviolet/ui';
2
+ import { useController } from 'react-hook-form';
2
3
  import { jsx } from '@emotion/react/jsx-runtime';
3
4
  import { useErrors } from '../../providers/ErrorContext/index.js';
4
- import { useFormField } from '../../hooks/useFormField.js';
5
5
 
6
6
  const RadioField = _ref => {
7
7
  let {
@@ -9,57 +9,54 @@ const RadioField = _ref => {
9
9
  'data-testid': dataTestId,
10
10
  disabled,
11
11
  id,
12
- label = '',
13
12
  name,
14
13
  onBlur,
14
+ label = '',
15
15
  onChange,
16
16
  onFocus,
17
17
  required,
18
- validate,
19
18
  value,
20
- tooltip
19
+ rules,
20
+ tooltip,
21
+ shouldUnregister = false
21
22
  } = _ref;
22
23
  const {
23
24
  getError
24
25
  } = useErrors();
25
26
  const {
26
- input,
27
- meta
28
- } = useFormField(name, {
29
- required,
30
- type: 'radio',
31
- validate,
32
- value
33
- });
34
- const error = getError({
35
- disabled,
36
- label: label,
37
- meta: meta,
27
+ field,
28
+ fieldState: {
29
+ error
30
+ }
31
+ } = useController({
38
32
  name,
39
- value: input.value
33
+ shouldUnregister,
34
+ rules: {
35
+ required,
36
+ ...rules
37
+ }
40
38
  });
41
39
  return jsx(Radio, {
42
- checked: input.checked,
40
+ name: field.name,
41
+ checked: field.value === value,
43
42
  className: className,
44
43
  "data-testid": dataTestId,
45
44
  disabled: disabled,
46
- error: error,
45
+ error: getError({
46
+ label: typeof label === 'string' ? label : ''
47
+ }, error),
47
48
  id: id,
48
- name: input.name,
49
- onChange: event => {
50
- input.onChange(event);
51
- onChange?.(event);
49
+ onChange: () => {
50
+ field.onChange(value);
51
+ onChange?.(value);
52
52
  },
53
53
  onBlur: event => {
54
- input.onBlur(event);
54
+ field.onBlur();
55
55
  onBlur?.(event);
56
56
  },
57
- onFocus: event => {
58
- input.onFocus(event);
59
- onFocus?.(event);
60
- },
57
+ onFocus: onFocus,
61
58
  required: required,
62
- value: input.value,
59
+ value: value ?? '',
63
60
  label: label,
64
61
  tooltip: tooltip
65
62
  });
@@ -1,7 +1,7 @@
1
1
  import { RadioGroup } from '@ultraviolet/ui';
2
+ import { useController } from 'react-hook-form';
2
3
  import { jsx } from '@emotion/react/jsx-runtime';
3
4
  import { useErrors } from '../../providers/ErrorContext/index.js';
4
- import { useFormField } from '../../hooks/useFormField.js';
5
5
 
6
6
  const RadioGroupField = _ref => {
7
7
  let {
@@ -10,41 +10,43 @@ const RadioGroupField = _ref => {
10
10
  name,
11
11
  onChange,
12
12
  required,
13
- validate,
14
- value,
13
+ rules,
15
14
  children,
15
+ label = '',
16
16
  error: customError,
17
17
  helper,
18
- direction
18
+ direction,
19
+ shouldUnregister = false
19
20
  } = _ref;
20
21
  const {
21
22
  getError
22
23
  } = useErrors();
23
24
  const {
24
- input,
25
- meta
26
- } = useFormField(name, {
27
- required,
28
- validate,
29
- value
30
- });
31
- const error = getError({
32
- label: legend,
33
- meta: meta,
25
+ field,
26
+ fieldState: {
27
+ error
28
+ }
29
+ } = useController({
34
30
  name,
35
- value: input.value
31
+ shouldUnregister,
32
+ rules: {
33
+ required,
34
+ ...rules
35
+ }
36
36
  });
37
37
  return jsx(RadioGroup, {
38
38
  className: className,
39
- name: input.name,
39
+ name: field.name,
40
40
  onChange: event => {
41
- input.onChange(event);
42
- onChange?.(event);
41
+ field.onChange(event);
42
+ onChange?.(event.target.value);
43
43
  },
44
44
  required: required,
45
- value: input.value,
45
+ value: field.value,
46
46
  legend: legend,
47
- error: error ?? customError,
47
+ error: getError({
48
+ label
49
+ }, error) ?? customError,
48
50
  helper: helper,
49
51
  direction: direction,
50
52
  children: children