@ultraviolet/form 1.0.0

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.
@@ -0,0 +1,138 @@
1
+ import { SelectInput } from '@ultraviolet/ui';
2
+ import { useMemo, Children, useCallback } from 'react';
3
+ import { jsx } from '@emotion/react/jsx-runtime';
4
+ import { useErrors } from '../../providers/ErrorContext/index.js';
5
+ import { useFormField } from '../../hooks/useFormField.js';
6
+
7
+ const identity = x => x;
8
+ const SelectInputField = _ref => {
9
+ let {
10
+ animation,
11
+ animationDuration,
12
+ animationOnChange,
13
+ children,
14
+ className,
15
+ disabled,
16
+ error: errorProp,
17
+ format: formatProp = identity,
18
+ formatOnBlur,
19
+ id,
20
+ inputId,
21
+ isClearable,
22
+ isLoading,
23
+ isSearchable,
24
+ label = '',
25
+ maxLength,
26
+ menuPortalTarget,
27
+ minLength,
28
+ multiple,
29
+ name,
30
+ onBlur,
31
+ onChange,
32
+ onFocus,
33
+ options: optionsProp,
34
+ parse: parseProp = identity,
35
+ placeholder,
36
+ readOnly,
37
+ required,
38
+ value,
39
+ noTopLabel,
40
+ noOptionsMessage,
41
+ customStyle,
42
+ 'data-testid': dataTestId
43
+ } = _ref;
44
+ const {
45
+ getError
46
+ } = useErrors();
47
+ const options = useMemo(() => optionsProp || Children.toArray(children).flat().filter(Boolean).map(_ref2 => {
48
+ let {
49
+ props: {
50
+ children: labelChild,
51
+ ...option
52
+ }
53
+ } = _ref2;
54
+ return {
55
+ ...option,
56
+ label: labelChild
57
+ };
58
+ }), [optionsProp, children]);
59
+ const parse = useMemo(() => multiple ? parseProp : option => parseProp(option?.value ?? null, name), [multiple, parseProp, name]);
60
+ const format = useCallback(val => {
61
+ if (multiple) return formatProp(val, name);
62
+ const find = (opts, valueToFind) => opts?.find(option => option.value === valueToFind);
63
+ let selected = '';
64
+ if (val && options) {
65
+ // TODO: find a proper way to simplify format with recursive options
66
+ selected = find(options, val);
67
+ if (!selected) {
68
+ selected = options.map(curr => find(curr.options, val)).filter(identity);
69
+ if (Array.isArray(selected) && selected.length === 0) {
70
+ selected = '';
71
+ }
72
+ }
73
+ }
74
+ return formatProp(selected, name);
75
+ }, [formatProp, multiple, name, options]);
76
+ const {
77
+ input,
78
+ meta
79
+ } = useFormField(name, {
80
+ disabled,
81
+ format,
82
+ formatOnBlur,
83
+ maxLength,
84
+ minLength: minLength || required ? 1 : undefined,
85
+ multiple,
86
+ parse,
87
+ required,
88
+ value
89
+ });
90
+ const error = getError({
91
+ errorProp,
92
+ label,
93
+ meta: meta,
94
+ name,
95
+ value: input.value
96
+ });
97
+ return jsx(SelectInput, {
98
+ animation: animation,
99
+ animationDuration: animationDuration,
100
+ animationOnChange: animationOnChange,
101
+ className: className,
102
+ disabled: disabled,
103
+ error: error,
104
+ id: id,
105
+ inputId: inputId,
106
+ isClearable: isClearable,
107
+ isLoading: isLoading,
108
+ isMulti: input.multiple,
109
+ customStyle: customStyle,
110
+ isSearchable: isSearchable,
111
+ menuPortalTarget: menuPortalTarget,
112
+ name: name,
113
+ onBlur: event => {
114
+ input.onBlur(event);
115
+ onBlur?.(event);
116
+ },
117
+ onChange: (event, action) => {
118
+ input.onChange(event);
119
+ onChange?.(event, action);
120
+ },
121
+ onFocus: event => {
122
+ input.onFocus(event);
123
+ onFocus?.(event);
124
+ },
125
+ options: options,
126
+ placeholder: placeholder,
127
+ readOnly: readOnly,
128
+ value: input.value,
129
+ noTopLabel: noTopLabel,
130
+ required: required,
131
+ noOptionsMessage: noOptionsMessage,
132
+ "data-testid": dataTestId,
133
+ children: children
134
+ });
135
+ };
136
+ SelectInputField.Option = SelectInput.Option;
137
+
138
+ export { SelectInputField };
@@ -0,0 +1,73 @@
1
+ import { SelectableCard } from '@ultraviolet/ui';
2
+ import { jsx } from '@emotion/react/jsx-runtime';
3
+ import { useErrors } from '../../providers/ErrorContext/index.js';
4
+ import { useFormField } from '../../hooks/useFormField.js';
5
+
6
+ const SelectableCardField = _ref => {
7
+ let {
8
+ name,
9
+ value,
10
+ onChange,
11
+ showTick,
12
+ type,
13
+ disabled,
14
+ children,
15
+ className,
16
+ onFocus,
17
+ onBlur,
18
+ required,
19
+ validate,
20
+ tooltip,
21
+ id,
22
+ label,
23
+ 'data-testid': dataTestId
24
+ } = _ref;
25
+ const {
26
+ getError
27
+ } = useErrors();
28
+ const {
29
+ input,
30
+ meta
31
+ } = useFormField(name, {
32
+ disabled,
33
+ required,
34
+ type: type ?? 'radio',
35
+ validate,
36
+ value
37
+ });
38
+ const error = getError({
39
+ label: name,
40
+ meta: meta,
41
+ name,
42
+ value: input.value
43
+ });
44
+ return jsx(SelectableCard, {
45
+ isError: !!error,
46
+ showTick: showTick,
47
+ checked: input.checked,
48
+ className: className,
49
+ disabled: disabled,
50
+ name: input.name,
51
+ onChange: event => {
52
+ input.onChange(event);
53
+ onChange?.(event);
54
+ },
55
+ onBlur: event => {
56
+ input.onBlur(event);
57
+ onBlur?.(event);
58
+ },
59
+ onFocus: event => {
60
+ input.onFocus(event);
61
+ onFocus?.(event);
62
+ },
63
+ type: type,
64
+ value: input.value,
65
+ id: id,
66
+ tooltip: tooltip,
67
+ label: label,
68
+ "data-testid": dataTestId,
69
+ children: children
70
+ });
71
+ };
72
+
73
+ export { SelectableCardField };
@@ -0,0 +1,49 @@
1
+ import { Button } from '@ultraviolet/ui';
2
+ import { useState, useEffect } from 'react';
3
+ import { useFormState } from 'react-final-form';
4
+ import { jsx } from '@emotion/react/jsx-runtime';
5
+
6
+ const Submit = _ref => {
7
+ let {
8
+ children,
9
+ className,
10
+ disabled = false,
11
+ icon,
12
+ iconPosition,
13
+ size,
14
+ variant = 'filled',
15
+ sentiment = 'success',
16
+ tooltip
17
+ } = _ref;
18
+ const {
19
+ invalid,
20
+ submitting,
21
+ hasValidationErrors,
22
+ dirtySinceLastSubmit
23
+ } = useFormState({
24
+ subscription: {
25
+ dirtySinceLastSubmit: true,
26
+ hasValidationErrors: true,
27
+ invalid: true,
28
+ submitting: true
29
+ }
30
+ });
31
+ const [isLoading, setIsLoading] = useState(true);
32
+ const isDisabled = disabled || submitting || isLoading || invalid && hasValidationErrors && !dirtySinceLastSubmit;
33
+ useEffect(() => setIsLoading(false), []);
34
+ return jsx(Button, {
35
+ className: className,
36
+ disabled: isDisabled,
37
+ icon: icon,
38
+ iconPosition: iconPosition,
39
+ isLoading: submitting,
40
+ size: size,
41
+ type: "submit",
42
+ variant: variant,
43
+ sentiment: sentiment,
44
+ tooltip: tooltip,
45
+ children: children
46
+ });
47
+ };
48
+
49
+ export { Submit };
@@ -0,0 +1,26 @@
1
+ import { Alert } from '@ultraviolet/ui';
2
+ import { FormSpy } from 'react-final-form';
3
+ import { jsx } from '@emotion/react/jsx-runtime';
4
+
5
+ const SubmitErrorAlert = _ref => {
6
+ let {
7
+ className
8
+ } = _ref;
9
+ return jsx(FormSpy, {
10
+ subscription: {
11
+ submitError: true
12
+ },
13
+ children: _ref2 => {
14
+ let {
15
+ submitError
16
+ } = _ref2;
17
+ return submitError ? jsx(Alert, {
18
+ className: className,
19
+ sentiment: "danger",
20
+ children: submitError
21
+ }) : null;
22
+ }
23
+ });
24
+ };
25
+
26
+ export { SubmitErrorAlert };
@@ -0,0 +1,45 @@
1
+ import { TagInput } from '@ultraviolet/ui';
2
+ import { jsx } from '@emotion/react/jsx-runtime';
3
+ import { useFormField } from '../../hooks/useFormField.js';
4
+
5
+ const TagInputField = _ref => {
6
+ let {
7
+ className,
8
+ 'data-testid': dataTestId,
9
+ disabled,
10
+ id,
11
+ name,
12
+ onChange,
13
+ placeholder,
14
+ required,
15
+ tags,
16
+ validate,
17
+ variant
18
+ } = _ref;
19
+ const {
20
+ input
21
+ } = useFormField(name, {
22
+ disabled,
23
+ required,
24
+ initialValue: tags,
25
+ type: 'text',
26
+ validate,
27
+ value: tags
28
+ });
29
+ return jsx(TagInput, {
30
+ className: className,
31
+ disabled: disabled,
32
+ id: id,
33
+ name: name,
34
+ onChange: event => {
35
+ onChange?.(event);
36
+ input.onChange(event);
37
+ },
38
+ placeholder: placeholder,
39
+ variant: variant,
40
+ tags: input.value,
41
+ "data-testid": dataTestId
42
+ });
43
+ };
44
+
45
+ export { TagInputField };
@@ -0,0 +1,154 @@
1
+ import { TextInput } from '@ultraviolet/ui';
2
+ import { forwardRef } from 'react';
3
+ import { jsx } from '@emotion/react/jsx-runtime';
4
+ import { useErrors } from '../../providers/ErrorContext/index.js';
5
+ import { useFormField } from '../../hooks/useFormField.js';
6
+
7
+ const TextInputField = /*#__PURE__*/forwardRef((_ref, ref) => {
8
+ let {
9
+ afterSubmit,
10
+ allowNull,
11
+ autoCapitalize,
12
+ autoComplete,
13
+ autoCorrect,
14
+ autoFocus,
15
+ autoSave,
16
+ beforeSubmit,
17
+ className,
18
+ cols,
19
+ 'data-testid': dataTestId,
20
+ defaultValue,
21
+ disabled,
22
+ fillAvailable,
23
+ format,
24
+ formatOnBlur,
25
+ generated,
26
+ id,
27
+ initialValue,
28
+ isEqual,
29
+ label = '',
30
+ max,
31
+ maxLength,
32
+ min,
33
+ minLength,
34
+ multiline,
35
+ multiple,
36
+ name,
37
+ noTopLabel,
38
+ notice,
39
+ onBlur,
40
+ onChange,
41
+ onFocus,
42
+ onKeyDown,
43
+ onKeyUp,
44
+ parse,
45
+ placeholder,
46
+ random,
47
+ readOnly,
48
+ regex,
49
+ required,
50
+ resizable,
51
+ rows,
52
+ subscription,
53
+ type,
54
+ unit,
55
+ size,
56
+ validate,
57
+ validateFields,
58
+ valid,
59
+ value
60
+ } = _ref;
61
+ const {
62
+ getError
63
+ } = useErrors();
64
+ const {
65
+ input,
66
+ meta
67
+ } = useFormField(name, {
68
+ afterSubmit,
69
+ allowNull,
70
+ beforeSubmit,
71
+ defaultValue,
72
+ disabled,
73
+ format,
74
+ formatOnBlur,
75
+ initialValue,
76
+ isEqual,
77
+ max,
78
+ maxLength,
79
+ min,
80
+ minLength,
81
+ multiple,
82
+ parse,
83
+ regex,
84
+ required,
85
+ subscription,
86
+ type,
87
+ validate,
88
+ validateFields,
89
+ value
90
+ });
91
+ const error = getError({
92
+ label,
93
+ max,
94
+ maxLength,
95
+ meta: meta,
96
+ min,
97
+ minLength,
98
+ name,
99
+ regex,
100
+ value: input.value
101
+ });
102
+ return jsx(TextInput, {
103
+ autoCapitalize: autoCapitalize,
104
+ autoComplete: autoComplete,
105
+ autoCorrect: autoCorrect,
106
+ autoFocus: autoFocus,
107
+ autoSave: autoSave,
108
+ className: className,
109
+ cols: cols,
110
+ "data-testid": dataTestId,
111
+ disabled: disabled,
112
+ error: error,
113
+ fillAvailable: fillAvailable,
114
+ generated: generated,
115
+ id: id,
116
+ label: label,
117
+ max: max,
118
+ maxLength: maxLength,
119
+ min: min,
120
+ minLength: minLength,
121
+ multiline: multiline,
122
+ name: input.name,
123
+ notice: notice,
124
+ onBlur: event => {
125
+ input.onBlur(event);
126
+ onBlur?.(event);
127
+ },
128
+ onChange: event => {
129
+ input.onChange(event);
130
+ onChange?.(event);
131
+ },
132
+ onFocus: event => {
133
+ input.onFocus(event);
134
+ onFocus?.(event);
135
+ },
136
+ onKeyUp: onKeyUp,
137
+ onKeyDown: onKeyDown,
138
+ placeholder: placeholder,
139
+ random: random,
140
+ readOnly: readOnly,
141
+ ref: ref,
142
+ required: required,
143
+ resizable: resizable,
144
+ rows: rows,
145
+ type: input.type,
146
+ value: input.value,
147
+ noTopLabel: noTopLabel,
148
+ unit: unit,
149
+ valid: valid,
150
+ size: size
151
+ });
152
+ });
153
+
154
+ export { TextInputField };
@@ -0,0 +1,90 @@
1
+ import { TimeInput } from '@ultraviolet/ui';
2
+ import { useMemo } from 'react';
3
+ import { jsx } from '@emotion/react/jsx-runtime';
4
+ import { useFormField } from '../../hooks/useFormField.js';
5
+
6
+ const parseTime = date => {
7
+ const timeStr = date && typeof date !== 'string' ? date.toLocaleTimeString().slice(0, -3) : '';
8
+ return {
9
+ label: timeStr,
10
+ value: timeStr
11
+ };
12
+ };
13
+ const TimeField = _ref => {
14
+ let {
15
+ required,
16
+ name,
17
+ schedule,
18
+ placeholder,
19
+ disabled,
20
+ initialValue,
21
+ validate,
22
+ readOnly,
23
+ value,
24
+ onChange,
25
+ onBlur,
26
+ onFocus,
27
+ isLoading,
28
+ isClearable,
29
+ inputId,
30
+ id,
31
+ formatOnBlur,
32
+ animation,
33
+ animationDuration,
34
+ animationOnChange,
35
+ className,
36
+ isSearchable,
37
+ options,
38
+ 'data-testid': dataTestId
39
+ } = _ref;
40
+ const {
41
+ input,
42
+ meta
43
+ } = useFormField(name, {
44
+ disabled,
45
+ formatOnBlur,
46
+ initialValue,
47
+ required,
48
+ validate,
49
+ value
50
+ });
51
+ const error = useMemo(() => input.value && meta.error ? meta.error : undefined, [input.value, meta.error]);
52
+ return jsx(TimeInput, {
53
+ placeholder: placeholder,
54
+ schedule: schedule,
55
+ required: required,
56
+ value: parseTime(input.value),
57
+ onChange: (val, action) => {
58
+ if (!val) return;
59
+ onChange?.(val, action);
60
+ const [hours, minutes] = val.value.split(':');
61
+ const date = input.value ? new Date(input.value) : new Date();
62
+ date.setHours(Number(hours), Number(minutes), 0);
63
+ input.onChange(date);
64
+ },
65
+ onBlur: event => {
66
+ input.onBlur(event);
67
+ onBlur?.(event);
68
+ },
69
+ onFocus: event => {
70
+ input.onFocus(event);
71
+ onFocus?.(event);
72
+ },
73
+ error: error,
74
+ disabled: disabled,
75
+ readOnly: readOnly,
76
+ animation: animation,
77
+ animationDuration: animationDuration,
78
+ animationOnChange: animationOnChange,
79
+ className: className,
80
+ isLoading: isLoading,
81
+ isClearable: isClearable,
82
+ isSearchable: isSearchable,
83
+ inputId: inputId,
84
+ id: id,
85
+ options: options,
86
+ "data-testid": dataTestId
87
+ });
88
+ };
89
+
90
+ export { TimeField };
@@ -0,0 +1,73 @@
1
+ import { Toggle } from '@ultraviolet/ui';
2
+ import { jsx } from '@emotion/react/jsx-runtime';
3
+ import { useFormField } from '../../hooks/useFormField.js';
4
+
5
+ const ToggleField = _ref => {
6
+ let {
7
+ afterSubmit,
8
+ allowNull,
9
+ beforeSubmit,
10
+ className,
11
+ data,
12
+ defaultValue,
13
+ disabled,
14
+ format,
15
+ formatOnBlur,
16
+ initialValue,
17
+ isEqual,
18
+ label,
19
+ multiple,
20
+ name,
21
+ onChange,
22
+ parse,
23
+ required,
24
+ size,
25
+ subscription,
26
+ tooltip,
27
+ validate,
28
+ validateFields,
29
+ value,
30
+ labelPosition,
31
+ 'data-testid': dataTestId
32
+ } = _ref;
33
+ const {
34
+ input
35
+ } = useFormField(name, {
36
+ afterSubmit,
37
+ allowNull,
38
+ beforeSubmit,
39
+ data,
40
+ defaultValue,
41
+ disabled,
42
+ format,
43
+ formatOnBlur,
44
+ initialValue,
45
+ isEqual,
46
+ multiple,
47
+ parse,
48
+ required,
49
+ subscription,
50
+ type: 'checkbox',
51
+ validate,
52
+ validateFields,
53
+ value
54
+ });
55
+ return jsx(Toggle, {
56
+ checked: input.checked,
57
+ tooltip: tooltip,
58
+ onChange: event => {
59
+ input.onChange(event);
60
+ onChange?.(event);
61
+ },
62
+ label: label,
63
+ size: size,
64
+ name: name,
65
+ disabled: disabled,
66
+ labelPosition: labelPosition,
67
+ className: className,
68
+ required: required,
69
+ "data-testid": dataTestId
70
+ });
71
+ };
72
+
73
+ export { ToggleField };
@@ -0,0 +1,8 @@
1
+ import validators from '../validators/index.js';
2
+
3
+ const pickValidators = args => Object.entries(args).map(_ref => {
4
+ let [key, value] = _ref;
5
+ return value !== undefined ? validators[key]?.(value) : undefined;
6
+ }).filter(validator => !!validator);
7
+
8
+ export { pickValidators };