@weareconceptstudio/form 0.0.3 → 0.0.5
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.
- package/dist/FormConfig.d.ts +5 -0
- package/dist/FormConfig.js +19 -0
- package/dist/checkbox/BaseCheckbox.d.ts +3 -0
- package/dist/checkbox/BaseCheckbox.js +51 -0
- package/dist/checkbox/index.js +15 -4
- package/dist/color-picker/index.d.ts +4 -1
- package/dist/color-picker/index.js +4 -4
- package/dist/date-picker/index.d.ts +6 -1
- package/dist/date-picker/index.js +4 -4
- package/dist/error-message/index.js +2 -2
- package/dist/form/BaseForm.d.ts +22 -20
- package/dist/form/BaseForm.js +38 -55
- package/dist/form/Builder/index.d.ts +9 -0
- package/dist/form/Builder/index.js +46 -0
- package/dist/form/Builder/style.d.ts +2 -0
- package/dist/form/Builder/style.js +3 -0
- package/dist/form/Item/index.d.ts +12 -10
- package/dist/form/Item/index.js +25 -18
- package/dist/form/hooks/rules.d.ts +3 -0
- package/dist/form/hooks/rules.js +44 -0
- package/dist/form/hooks/useEvent.d.ts +1 -0
- package/dist/form/hooks/useEvent.js +12 -0
- package/dist/form/hooks/useFormInstance.js +3 -0
- package/dist/form/hooks/useInput.d.ts +12 -0
- package/dist/form/hooks/useInput.js +46 -0
- package/dist/form/index.d.ts +6 -17
- package/dist/form/index.js +3 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/input/BaseInput/index.d.ts +4 -2
- package/dist/input/BaseInput/index.js +13 -31
- package/dist/input/Input.d.ts +4 -1
- package/dist/input/Input.js +15 -16
- package/dist/input/Number/index.d.ts +4 -1
- package/dist/input/Number/index.js +27 -4
- package/dist/input/Password/icons.d.ts +1 -1
- package/dist/input/Password/icons.js +6 -6
- package/dist/input/Password/index.d.ts +4 -1
- package/dist/input/Password/index.js +5 -5
- package/dist/input/TextArea/index.d.ts +4 -1
- package/dist/input/TextArea/index.js +8 -9
- package/dist/input/index.d.ts +10 -1
- package/dist/input/index.js +6 -4
- package/dist/phone-number/index.d.ts +7 -0
- package/dist/phone-number/index.js +13 -0
- package/dist/radio/BaseRadio.js +18 -5
- package/dist/radio/Group.js +19 -2
- package/dist/radio/index.js +2 -2
- package/dist/select/icons.d.ts +3 -0
- package/dist/select/icons.js +6 -0
- package/dist/select/index.d.ts +4 -1
- package/dist/select/index.js +57 -20
- package/dist/styles/formStyle.d.ts +2 -0
- package/dist/styles/formStyle.js +585 -0
- package/dist/styles/theme.d.ts +2 -0
- package/dist/styles/theme.js +113 -0
- package/dist/styles/variables.d.ts +2 -0
- package/dist/styles/variables.js +246 -0
- package/dist/translations/en.d.ts +52 -0
- package/dist/translations/en.js +52 -0
- package/dist/translations/index.d.ts +54 -0
- package/dist/translations/index.js +2 -0
- package/dist/upload/UploadButton/index.d.ts +3 -0
- package/dist/upload/UploadButton/index.js +41 -0
- package/dist/upload/UploadButton/style.d.ts +2 -0
- package/dist/upload/UploadButton/style.js +24 -0
- package/dist/upload/UploadList/ListItem/index.d.ts +5 -0
- package/dist/upload/UploadList/ListItem/index.js +11 -0
- package/dist/upload/UploadList/index.d.ts +3 -0
- package/dist/upload/UploadList/index.js +11 -0
- package/dist/upload/UploadList/style.d.ts +2 -0
- package/dist/upload/UploadList/style.js +13 -0
- package/dist/upload/index.d.ts +4 -1
- package/dist/upload/index.js +15 -5
- package/dist/upload/utils.d.ts +9 -0
- package/dist/upload/utils.js +64 -0
- package/package.json +31 -34
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { useTranslation } from '@weareconceptstudio/core';
|
|
3
|
+
import { ThemeProvider } from 'styled-components';
|
|
4
|
+
//* Translations
|
|
5
|
+
import translations from './translations';
|
|
6
|
+
//* Styles
|
|
7
|
+
import theme from './styles/theme';
|
|
8
|
+
import FormVariables from './styles/variables';
|
|
9
|
+
import FormStyle from './styles/formStyle';
|
|
10
|
+
export const FormConfig = ({ fontFamily = 'core_Font', children }) => {
|
|
11
|
+
const { addTranslation } = useTranslation();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
addTranslation(translations, 'prepend');
|
|
14
|
+
}, []);
|
|
15
|
+
return (React.createElement(ThemeProvider, { theme: theme },
|
|
16
|
+
React.createElement(FormVariables, { fontFamily: fontFamily }),
|
|
17
|
+
React.createElement(FormStyle, null),
|
|
18
|
+
children));
|
|
19
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
|
|
2
|
+
import { useMergedState } from '@weareconceptstudio/core';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
const BaseCheckbox = forwardRef((props, ref) => {
|
|
5
|
+
const { prefixCls = 'checkbox', className, style, checked, disabled, defaultChecked = false, type = 'checkbox', title, onChange, ...inputProps } = props;
|
|
6
|
+
const inputRef = useRef(null);
|
|
7
|
+
const holderRef = useRef(null);
|
|
8
|
+
const [rawValue, setRawValue] = useMergedState(defaultChecked, {
|
|
9
|
+
value: checked,
|
|
10
|
+
});
|
|
11
|
+
useImperativeHandle(ref, () => ({
|
|
12
|
+
focus: (options) => {
|
|
13
|
+
inputRef.current?.focus(options);
|
|
14
|
+
},
|
|
15
|
+
blur: () => {
|
|
16
|
+
inputRef.current?.blur();
|
|
17
|
+
},
|
|
18
|
+
input: inputRef.current,
|
|
19
|
+
nativeElement: holderRef.current,
|
|
20
|
+
}));
|
|
21
|
+
const classString = classNames(prefixCls, className, {
|
|
22
|
+
[`${prefixCls}-checked`]: rawValue,
|
|
23
|
+
[`${prefixCls}-disabled`]: disabled,
|
|
24
|
+
});
|
|
25
|
+
const handleChange = (e) => {
|
|
26
|
+
if (disabled) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!('checked' in props)) {
|
|
30
|
+
setRawValue(e.target.checked);
|
|
31
|
+
}
|
|
32
|
+
onChange?.({
|
|
33
|
+
target: {
|
|
34
|
+
...props,
|
|
35
|
+
type,
|
|
36
|
+
checked: e.target.checked,
|
|
37
|
+
},
|
|
38
|
+
stopPropagation() {
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
},
|
|
41
|
+
preventDefault() {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
},
|
|
44
|
+
nativeEvent: e.nativeEvent,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
return (React.createElement("span", { className: classString, title: title, style: style, ref: holderRef },
|
|
48
|
+
React.createElement("input", { type: type, className: `${prefixCls}-input`, ref: inputRef, onChange: handleChange, disabled: disabled, checked: !!rawValue, ...inputProps }),
|
|
49
|
+
React.createElement("span", { className: `${prefixCls}-inner` })));
|
|
50
|
+
});
|
|
51
|
+
export default BaseCheckbox;
|
package/dist/checkbox/index.js
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import BaseCheckbox from './BaseCheckbox';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
const Checkbox = forwardRef((props, forwardRef) => {
|
|
5
|
+
const { type = 'checkbox', prefixCls = 'checkbox', children, ...restProps } = props;
|
|
6
|
+
const checkboxProps = {
|
|
7
|
+
ref: forwardRef,
|
|
8
|
+
...restProps,
|
|
9
|
+
};
|
|
10
|
+
const classString = classNames(`${prefixCls}-wrapper`, {
|
|
11
|
+
[`${prefixCls}-wrapper-checked`]: checkboxProps.checked,
|
|
12
|
+
[`${prefixCls}-wrapper-disabled`]: checkboxProps.disabled,
|
|
13
|
+
});
|
|
14
|
+
return (React.createElement("label", { className: classString },
|
|
15
|
+
React.createElement(BaseCheckbox, { ...checkboxProps }),
|
|
16
|
+
children !== undefined && React.createElement("span", { className: `${prefixCls}-content` }, children)));
|
|
6
17
|
});
|
|
7
18
|
if (process.env.NODE_ENV !== 'production') {
|
|
8
19
|
Checkbox.displayName = 'Checkbox';
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export default ColorPicker;
|
|
2
|
-
declare
|
|
2
|
+
declare function ColorPicker(props: any): React.JSX.Element;
|
|
3
|
+
declare namespace ColorPicker {
|
|
4
|
+
let displayName: string;
|
|
5
|
+
}
|
|
3
6
|
import React from 'react';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React
|
|
2
|
-
const ColorPicker =
|
|
3
|
-
return
|
|
4
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
const ColorPicker = (props) => {
|
|
3
|
+
return React.createElement("input", { type: 'color' });
|
|
4
|
+
};
|
|
5
5
|
if (process.env.NODE_ENV !== 'production') {
|
|
6
6
|
ColorPicker.displayName = 'ColorPicker';
|
|
7
7
|
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
export default DatePicker;
|
|
2
|
-
declare
|
|
2
|
+
declare function DatePicker({ type }: {
|
|
3
|
+
type?: string;
|
|
4
|
+
}): React.JSX.Element;
|
|
5
|
+
declare namespace DatePicker {
|
|
6
|
+
let displayName: string;
|
|
7
|
+
}
|
|
3
8
|
import React from 'react';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
/*
|
|
3
3
|
types - default=date,datetime-local,month,time,week
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
const DatePicker =
|
|
7
|
-
return
|
|
8
|
-
}
|
|
6
|
+
const DatePicker = ({ type = 'date' }) => {
|
|
7
|
+
return React.createElement("input", { type: type });
|
|
8
|
+
};
|
|
9
9
|
if (process.env.NODE_ENV !== 'production') {
|
|
10
10
|
DatePicker.displayName = 'DatePicker';
|
|
11
11
|
}
|
|
@@ -13,10 +13,10 @@ const ErrorMessage = ({ as, errors, name, message, render, ...rest }) => {
|
|
|
13
13
|
return isValidElement(as)
|
|
14
14
|
? cloneElement(as, props)
|
|
15
15
|
: render
|
|
16
|
-
?
|
|
16
|
+
? render({
|
|
17
17
|
message: messageFromRegister || message,
|
|
18
18
|
messages: types,
|
|
19
|
-
})
|
|
19
|
+
})
|
|
20
20
|
: createElement(as || Fragment, props);
|
|
21
21
|
};
|
|
22
22
|
if (process.env.NODE_ENV !== 'production') {
|
package/dist/form/BaseForm.d.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
mode?:
|
|
9
|
-
reValidateMode
|
|
10
|
-
errors
|
|
11
|
-
resetOptions
|
|
12
|
-
criteriaMode
|
|
13
|
-
shouldFocusError
|
|
14
|
-
delayError
|
|
15
|
-
shouldUseNativeValidation
|
|
16
|
-
shouldUnregister
|
|
17
|
-
|
|
18
|
-
declare namespace BaseForm {
|
|
19
|
-
let displayName: string;
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { FieldValues } from 'react-hook-form';
|
|
3
|
+
interface BaseFormProps<T extends FieldValues> {
|
|
4
|
+
initialValues?: T;
|
|
5
|
+
values?: T;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
onSubmit: (values: T) => Promise<any>;
|
|
8
|
+
mode?: 'onChange' | 'onBlur' | 'onSubmit' | 'all';
|
|
9
|
+
reValidateMode?: 'onChange' | 'onBlur' | 'onSubmit';
|
|
10
|
+
errors?: any;
|
|
11
|
+
resetOptions?: Record<string, any>;
|
|
12
|
+
criteriaMode?: 'firstError' | 'all';
|
|
13
|
+
shouldFocusError?: boolean;
|
|
14
|
+
delayError?: number;
|
|
15
|
+
shouldUseNativeValidation?: boolean;
|
|
16
|
+
shouldUnregister?: boolean;
|
|
17
|
+
className?: string;
|
|
20
18
|
}
|
|
21
|
-
|
|
19
|
+
declare const BaseForm: {
|
|
20
|
+
<T extends FieldValues>({ initialValues: defaultValues, values, children, onSubmit: onFinish, mode, reValidateMode, errors, resetOptions, criteriaMode, shouldFocusError, delayError, shouldUseNativeValidation, shouldUnregister, className, }: BaseFormProps<T>): React.JSX.Element;
|
|
21
|
+
displayName: string;
|
|
22
|
+
};
|
|
23
|
+
export default BaseForm;
|
package/dist/form/BaseForm.js
CHANGED
|
@@ -1,67 +1,50 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { FormProvider, useForm } from
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// children: React elements
|
|
7
|
-
// onSubmit: func (values) => {}
|
|
8
|
-
// layout: vertical | horizontal
|
|
9
|
-
// mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
|
|
10
|
-
// reValidateMode: onChange | onBlur | onSubmit = 'onChange'
|
|
11
|
-
// errors: Reactive errors to update the form errors.
|
|
12
|
-
// resetOptions: Option to reset form state update while updating new form values.
|
|
13
|
-
// criteriaMode: Display all validation errors or one at a time. (firstError | all)
|
|
14
|
-
// shouldFocusError: Enable or disable built-in focus management.
|
|
15
|
-
// delayError: Delay error from appearing instantly.
|
|
16
|
-
// shouldUseNativeValidation: Use browser built-in form constraint API.
|
|
17
|
-
// shouldUnregister: Enable and disable input unregister after unmount.
|
|
18
|
-
/**
|
|
19
|
-
* defaultValues are cached. To reset them, use the reset API.
|
|
20
|
-
* defaultValues will be included in the submission result by default.
|
|
21
|
-
* values will get updated when values props updates
|
|
22
|
-
* resetOptions: {
|
|
23
|
-
keepDirtyValues: true, // user-interacted input will be retained
|
|
24
|
-
keepErrors: true, // input errors will be retained with value update
|
|
25
|
-
},
|
|
26
|
-
* criteriaMode:{
|
|
27
|
-
When set to firstError (default), only the first error from each field will be gathered.
|
|
28
|
-
When set to all, all errors from each field will be gathered.
|
|
29
|
-
}
|
|
30
|
-
* shouldFocusError: When set to true (default), and the user submits a form that fails validation, focus is set on the first field with an error.
|
|
31
|
-
* delayError: number
|
|
32
|
-
*
|
|
33
|
-
*/
|
|
34
|
-
const StyledForm = styled.form `
|
|
35
|
-
&.vertical {
|
|
36
|
-
.form-item-row {
|
|
37
|
-
flex-direction: column;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.form-item-row {
|
|
42
|
-
display: flex;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.form-item {
|
|
46
|
-
margin-bottom: 24px;
|
|
47
|
-
}
|
|
48
|
-
`;
|
|
49
|
-
const BaseForm = ({ initialValues: defaultValues, values, children, onSubmit, layout = 'vertical', mode = 'onChange', reValidateMode, errors, resetOptions, criteriaMode, shouldFocusError, delayError, shouldUseNativeValidation, shouldUnregister, }) => {
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { FormProvider, useForm } from 'react-hook-form';
|
|
3
|
+
import { Text } from '@weareconceptstudio/core';
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
const BaseForm = ({ initialValues: defaultValues, values, children, onSubmit: onFinish, mode = 'onChange', reValidateMode = 'onChange', errors, resetOptions, criteriaMode, shouldFocusError, delayError = 0, shouldUseNativeValidation, shouldUnregister, className, }) => {
|
|
50
6
|
const methods = useForm({
|
|
51
|
-
defaultValues,
|
|
52
|
-
values,
|
|
53
7
|
mode,
|
|
54
|
-
reValidateMode,
|
|
55
8
|
errors,
|
|
9
|
+
values,
|
|
10
|
+
delayError,
|
|
56
11
|
resetOptions,
|
|
57
12
|
criteriaMode,
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
defaultValues,
|
|
15
|
+
reValidateMode,
|
|
58
16
|
shouldFocusError,
|
|
59
|
-
delayError,
|
|
60
|
-
shouldUseNativeValidation,
|
|
61
17
|
shouldUnregister,
|
|
18
|
+
shouldUseNativeValidation,
|
|
62
19
|
});
|
|
20
|
+
const onSubmit = useCallback((values) => {
|
|
21
|
+
return onFinish(values).catch(({ data, status, ...err }) => {
|
|
22
|
+
if (status === 422) {
|
|
23
|
+
for (const key in data.errors) {
|
|
24
|
+
if (data.errors.hasOwnProperty(key)) {
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
methods.setError(key, {
|
|
27
|
+
type: 'manual',
|
|
28
|
+
message: data.errors[key][0],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
methods.setError('root.serverError', {
|
|
35
|
+
type: String(status),
|
|
36
|
+
message: data?.message || 'serverError',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}, [methods, onFinish]);
|
|
63
41
|
return (React.createElement(FormProvider, { ...methods },
|
|
64
|
-
React.createElement(
|
|
42
|
+
methods.formState.errors.root?.serverError && (React.createElement("div", { className: "global-error-wrap" },
|
|
43
|
+
React.createElement(Text, { className: 'backend-error', text: methods.formState.errors.root?.serverError.message }),
|
|
44
|
+
React.createElement(Text, { className: 'frontend-error', text: 'globalError' }))),
|
|
45
|
+
React.createElement("form", { onSubmit: methods.handleSubmit(onSubmit), className: classNames({
|
|
46
|
+
[className]: !!className,
|
|
47
|
+
}) }, children)));
|
|
65
48
|
};
|
|
66
49
|
if (process.env.NODE_ENV !== 'production') {
|
|
67
50
|
BaseForm.displayName = 'BaseForm';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default FormBuilder;
|
|
2
|
+
declare function FormBuilder({ className, onSubmit, formOptions, fields, children }: {
|
|
3
|
+
className?: string;
|
|
4
|
+
onSubmit: any;
|
|
5
|
+
formOptions?: {};
|
|
6
|
+
fields?: any[];
|
|
7
|
+
children: any;
|
|
8
|
+
}): React.JSX.Element;
|
|
9
|
+
import React from 'react';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useMemo, cloneElement, isValidElement } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
//* Components
|
|
4
|
+
import Form from '../';
|
|
5
|
+
import Input from '../../input';
|
|
6
|
+
import Checkbox from '../../checkbox';
|
|
7
|
+
import Radio from '../../radio';
|
|
8
|
+
import PhoneNumber from '../../phone-number';
|
|
9
|
+
import Select from '../../select';
|
|
10
|
+
import Upload from '../../upload';
|
|
11
|
+
import DatePicker from '../../date-picker';
|
|
12
|
+
import ColorPicker from '../../color-picker';
|
|
13
|
+
//* Style
|
|
14
|
+
import BuilderStyle from './style';
|
|
15
|
+
const formElements = {
|
|
16
|
+
'input': React.createElement(Input, null),
|
|
17
|
+
'password': React.createElement(Input.Password, null),
|
|
18
|
+
'textarea': React.createElement(Input.TextArea, null),
|
|
19
|
+
'number': React.createElement(Input.Number, null),
|
|
20
|
+
'checkbox': React.createElement(Checkbox, null),
|
|
21
|
+
'radio': React.createElement(Radio, null),
|
|
22
|
+
'phone': React.createElement(PhoneNumber, null),
|
|
23
|
+
'select': React.createElement(Select, null),
|
|
24
|
+
'upload': React.createElement(Upload, null),
|
|
25
|
+
'date': React.createElement(DatePicker, null),
|
|
26
|
+
'color': React.createElement(ColorPicker, null),
|
|
27
|
+
};
|
|
28
|
+
const FormBuilder = ({ className = '', onSubmit, formOptions = {}, fields = [], children }) => {
|
|
29
|
+
const elements = useMemo(() => {
|
|
30
|
+
return fields.map((field, index) => {
|
|
31
|
+
if (field.fieldType == 'empty') {
|
|
32
|
+
return (React.createElement("div", { className: 'empty-form-item', ...field.fieldProps }));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return isValidElement(formElements[field.fieldType]) ? (React.createElement(Form.Item, { key: index, ...field.labelProps }, cloneElement(formElements[field.fieldType], field.fieldProps))) : null;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}, [fields]);
|
|
39
|
+
const classString = classNames('form-builder', {
|
|
40
|
+
[className]: className,
|
|
41
|
+
});
|
|
42
|
+
return (React.createElement(Form, { ...formOptions, onSubmit: onSubmit },
|
|
43
|
+
React.createElement(BuilderStyle, { className: classString }, elements),
|
|
44
|
+
children));
|
|
45
|
+
};
|
|
46
|
+
export default FormBuilder;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export default BuilderStyle;
|
|
2
|
+
declare const BuilderStyle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
label
|
|
4
|
-
name:
|
|
5
|
-
children:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
interface FormItemProps {
|
|
3
|
+
label?: string;
|
|
4
|
+
name: string;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
errorKey?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
requiredMessage?: string;
|
|
10
|
+
rules?: Array<any>;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
declare const FormItem: React.FC<FormItemProps>;
|
|
13
|
+
export default FormItem;
|
package/dist/form/Item/index.js
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
import React, { cloneElement, isValidElement } from 'react';
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
2
|
+
import lodashGet from 'lodash.get';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import { useTranslation } from '@weareconceptstudio/core';
|
|
5
5
|
import ErrorMessage from '../../error-message';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { useInput } from '../hooks/useInput';
|
|
7
|
+
import { useRules } from '../hooks/rules';
|
|
8
|
+
const FormItem = ({ label, name, children, className, errorKey, required = true, requiredMessage, rules = [], }) => {
|
|
9
|
+
const { translate } = useTranslation();
|
|
10
|
+
const { formState } = useInput({
|
|
11
|
+
name,
|
|
12
|
+
rules: useRules({ rules, required, requiredMessage }),
|
|
13
|
+
errorKey: errorKey || label,
|
|
14
|
+
});
|
|
15
|
+
const hasError = !!lodashGet(formState.errors, name);
|
|
16
|
+
const classString = classNames('form-item', {
|
|
17
|
+
[className]: className,
|
|
18
|
+
'has-error': hasError,
|
|
19
|
+
disabled: isValidElement(children) && children.props.disabled,
|
|
20
|
+
});
|
|
21
|
+
return (React.createElement("div", { className: classString },
|
|
10
22
|
React.createElement("div", { className: "form-item-row" },
|
|
11
|
-
React.createElement("div", { className: "form-item-label" },
|
|
12
|
-
React.createElement("label", { htmlFor: name },
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
})),
|
|
18
|
-
React.createElement(ErrorMessage, { name: name, as: React.createElement("div", { className: 'error-message' }) }))));
|
|
23
|
+
label ? (React.createElement("div", { className: "form-item-label" },
|
|
24
|
+
React.createElement("label", { htmlFor: name, "data-required": required },
|
|
25
|
+
translate(label),
|
|
26
|
+
required ? React.createElement("span", { className: "required-symbol" }, "*") : null))) : null,
|
|
27
|
+
React.createElement("div", { className: "form-item-control" }, isValidElement(children) && cloneElement(children, { name })),
|
|
28
|
+
React.createElement(ErrorMessage, { name: name, as: React.createElement("div", { className: "error-message" }) }))));
|
|
19
29
|
};
|
|
20
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
21
|
-
FormItem.displayName = 'FormItem';
|
|
22
|
-
}
|
|
23
30
|
export default FormItem;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { useTranslation } from '@weareconceptstudio/core';
|
|
3
|
+
export const validationPatterns = (type, pattern) => {
|
|
4
|
+
switch (type) {
|
|
5
|
+
case 'email':
|
|
6
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/g;
|
|
7
|
+
case 'number':
|
|
8
|
+
return /[0-9]/g;
|
|
9
|
+
default:
|
|
10
|
+
return pattern;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const useRules = (props) => {
|
|
14
|
+
return useMemo(() => {
|
|
15
|
+
let r = [...props.rules];
|
|
16
|
+
if (props.required) {
|
|
17
|
+
r.unshift({ required: true, message: props.requiredMessage });
|
|
18
|
+
}
|
|
19
|
+
return r;
|
|
20
|
+
}, [props]);
|
|
21
|
+
};
|
|
22
|
+
export const mapValidationRules = (errorKey, rules) => {
|
|
23
|
+
const { translate } = useTranslation();
|
|
24
|
+
return rules?.reduce((acc, rule) => {
|
|
25
|
+
if (rule.required) {
|
|
26
|
+
acc.required = rule.message || translate('validateMessages.required', { errorKey: translate(errorKey) });
|
|
27
|
+
}
|
|
28
|
+
if (rule.pattern || rule.type) {
|
|
29
|
+
acc.pattern = { value: validationPatterns(rule.type, rule.pattern), message: rule.message || 'Invalid format' };
|
|
30
|
+
}
|
|
31
|
+
if (rule.minLength) {
|
|
32
|
+
acc.minLength = { value: rule.minLength, message: rule.message || `Minimum length is ${rule.minLength}` };
|
|
33
|
+
}
|
|
34
|
+
if (rule.maxLength) {
|
|
35
|
+
acc.maxLength = { value: rule.maxLength, message: rule.message || `Maximum length is ${rule.maxLength}` };
|
|
36
|
+
}
|
|
37
|
+
if (rule.validator) {
|
|
38
|
+
acc.validate = async (value) => {
|
|
39
|
+
return (await rule.validator(value)) || rule.message || 'Validation failed';
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return acc;
|
|
43
|
+
}, {});
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useEvent: <Args extends unknown[], Return>(fn: (...args: Args) => Return) => (...args: Args) => Return;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
const useLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
4
|
+
export const useEvent = (fn) => {
|
|
5
|
+
const ref = React.useRef(() => {
|
|
6
|
+
throw new Error('Cannot call an event handler while rendering.');
|
|
7
|
+
});
|
|
8
|
+
useLayoutEffect(() => {
|
|
9
|
+
ref.current = fn;
|
|
10
|
+
});
|
|
11
|
+
return useCallback((...args) => ref.current(...args), []);
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const useInput: (props: any) => {
|
|
2
|
+
field: {
|
|
3
|
+
value: any;
|
|
4
|
+
onBlur: (...args: unknown[]) => void;
|
|
5
|
+
onChange: (...args: any[]) => void;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
name: any;
|
|
8
|
+
ref: import("react-hook-form").RefCallBack;
|
|
9
|
+
};
|
|
10
|
+
fieldState: import("react-hook-form").ControllerFieldState;
|
|
11
|
+
formState: import("react-hook-form").UseFormStateReturn<import("react-hook-form").FieldValues>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useController } from 'react-hook-form';
|
|
2
|
+
import { useEvent } from './useEvent';
|
|
3
|
+
import { mapValidationRules } from './rules';
|
|
4
|
+
const defaultFormat = (value) => (value == null ? '' : value);
|
|
5
|
+
const defaultParse = (value) => (value === '' ? null : value);
|
|
6
|
+
export const useInput = (props) => {
|
|
7
|
+
const { defaultValue, name, onBlur: initialOnBlur, onChange: initialOnChange, format = defaultFormat, parse = defaultParse, multiple, errorKey, rules = [] } = props;
|
|
8
|
+
const { field: controllerField, fieldState, formState, } = useController({
|
|
9
|
+
name,
|
|
10
|
+
defaultValue,
|
|
11
|
+
rules: mapValidationRules(errorKey, rules),
|
|
12
|
+
});
|
|
13
|
+
const onBlur = useEvent((...event) => {
|
|
14
|
+
controllerField.onBlur();
|
|
15
|
+
if (initialOnBlur) {
|
|
16
|
+
initialOnBlur(...event);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const onChange = useEvent((...event) => {
|
|
20
|
+
let eventOrValue;
|
|
21
|
+
if (props.type == 'checkbox' && event[0]?.target?.value === 'on') {
|
|
22
|
+
eventOrValue = event[0].target.checked;
|
|
23
|
+
}
|
|
24
|
+
else if (props.type == 'select') {
|
|
25
|
+
eventOrValue = multiple ? event[0].map((ev) => ev.value) : event[0]?.value;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
eventOrValue = event[0]?.target?.value ?? event[0];
|
|
29
|
+
}
|
|
30
|
+
controllerField.onChange(parse ? parse(eventOrValue) : eventOrValue);
|
|
31
|
+
if (initialOnChange) {
|
|
32
|
+
initialOnChange(...event);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const field = {
|
|
36
|
+
...controllerField,
|
|
37
|
+
value: format ? format(controllerField.value) : controllerField.value,
|
|
38
|
+
onBlur,
|
|
39
|
+
onChange,
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
field,
|
|
43
|
+
fieldState,
|
|
44
|
+
formState,
|
|
45
|
+
};
|
|
46
|
+
};
|
package/dist/form/index.d.ts
CHANGED
|
@@ -1,18 +1,7 @@
|
|
|
1
|
+
import BaseForm from './BaseForm';
|
|
2
|
+
import Item from './Item';
|
|
3
|
+
type FormComponent<T> = typeof BaseForm & {
|
|
4
|
+
Item: typeof Item;
|
|
5
|
+
};
|
|
6
|
+
declare const Form: FormComponent<any>;
|
|
1
7
|
export default Form;
|
|
2
|
-
declare function Form({ initialValues: defaultValues, values, children, onSubmit, layout, mode, reValidateMode, errors, resetOptions, criteriaMode, shouldFocusError, delayError, shouldUseNativeValidation, shouldUnregister, }: {
|
|
3
|
-
initialValues: any;
|
|
4
|
-
values: any;
|
|
5
|
-
children: any;
|
|
6
|
-
onSubmit: any;
|
|
7
|
-
layout?: string;
|
|
8
|
-
mode?: string;
|
|
9
|
-
reValidateMode: any;
|
|
10
|
-
errors: any;
|
|
11
|
-
resetOptions: any;
|
|
12
|
-
criteriaMode: any;
|
|
13
|
-
shouldFocusError: any;
|
|
14
|
-
delayError: any;
|
|
15
|
-
shouldUseNativeValidation: any;
|
|
16
|
-
shouldUnregister: any;
|
|
17
|
-
}): import("react").JSX.Element;
|
|
18
|
-
declare namespace Form { }
|
package/dist/form/index.js
CHANGED