@carefrees/form-utils-react-native 0.0.7
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/README.md +7 -0
- package/package.json +31 -0
- package/src/formItem/index.tsx +102 -0
- package/src/formList/index.tsx +62 -0
- package/src/hooks/attr/attr.FormItem.tsx +131 -0
- package/src/hooks/useAttrs.ts +42 -0
- package/src/index.tsx +80 -0
- package/src/layout/index.tsx +146 -0
- package/src/layout/layout.formItem.tsx +205 -0
- package/src/styles/index.ts +203 -0
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@carefrees/form-utils-react-native",
|
|
3
|
+
"author": "SunLxy <1011771396@qq.com>",
|
|
4
|
+
"description": "react-native 表单组件",
|
|
5
|
+
"homepage": "https://github.com/SunLxy/carefrees-form-utils",
|
|
6
|
+
"version": "0.0.7",
|
|
7
|
+
"main": "esm/index.js",
|
|
8
|
+
"types": "esm/index.d.ts",
|
|
9
|
+
"module": "esm/index.js",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "carefrees-rslib build",
|
|
13
|
+
"watch": "carefrees-rslib build --watch"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"src",
|
|
20
|
+
"esm"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@carefrees/form-utils": "^0.0.7",
|
|
24
|
+
"@carefrees/form-utils-react-hooks": "^0.0.7"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"react-native": "0.76.9",
|
|
28
|
+
"@types/react": "18.2.21",
|
|
29
|
+
"react": "^18.2.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { LayoutFormItem, LayoutFormItemProps } from '../layout/layout.formItem';
|
|
2
|
+
import { useFormItemAttr, FormItemAttrOptions } from '../hooks/attr/attr.FormItem';
|
|
3
|
+
import { Fragment, memo } from 'react';
|
|
4
|
+
import { useRegisterFormHideItem, FormItemParentNameProvider } from '@carefrees/form-utils-react-hooks';
|
|
5
|
+
|
|
6
|
+
export interface FormItemProps extends FormItemAttrOptions, LayoutFormItemProps {
|
|
7
|
+
/**不进行样式渲染*/
|
|
8
|
+
noStyle?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**表单项基础实例*/
|
|
12
|
+
const FormItemInstance = memo((props: FormItemProps) => {
|
|
13
|
+
const {
|
|
14
|
+
labelMode,
|
|
15
|
+
noStyle,
|
|
16
|
+
onlyRuleStyle,
|
|
17
|
+
label,
|
|
18
|
+
helpText,
|
|
19
|
+
extra,
|
|
20
|
+
errorLayout,
|
|
21
|
+
required,
|
|
22
|
+
showColon,
|
|
23
|
+
colSpan,
|
|
24
|
+
rowSpan,
|
|
25
|
+
...rest
|
|
26
|
+
} = props;
|
|
27
|
+
const { children, ruleInstance, formItemInstance, htmlFor, validateResult } = useFormItemAttr({ ...rest });
|
|
28
|
+
if (noStyle) {
|
|
29
|
+
return (
|
|
30
|
+
<FormItemParentNameProvider name={formItemInstance.name} sort={formItemInstance.sort}>
|
|
31
|
+
{children}
|
|
32
|
+
</FormItemParentNameProvider>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return (
|
|
36
|
+
<FormItemParentNameProvider name={formItemInstance.name} sort={formItemInstance.sort}>
|
|
37
|
+
<LayoutFormItem
|
|
38
|
+
labelMode={labelMode}
|
|
39
|
+
onlyRuleStyle={onlyRuleStyle}
|
|
40
|
+
required={required || ruleInstance?.isRequired?.()}
|
|
41
|
+
label={label}
|
|
42
|
+
helpText={helpText}
|
|
43
|
+
extra={extra}
|
|
44
|
+
errorLayout={errorLayout}
|
|
45
|
+
showColon={showColon}
|
|
46
|
+
colSpan={colSpan}
|
|
47
|
+
rowSpan={rowSpan}
|
|
48
|
+
htmlFor={htmlFor}
|
|
49
|
+
validateResult={validateResult}
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
</LayoutFormItem>
|
|
53
|
+
</FormItemParentNameProvider>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**表单项*/
|
|
58
|
+
export const FormItem = memo((props: Partial<FormItemProps>) => {
|
|
59
|
+
const { name } = props;
|
|
60
|
+
if (name) {
|
|
61
|
+
return <FormItemInstance {...props} name={name} />;
|
|
62
|
+
}
|
|
63
|
+
const {
|
|
64
|
+
labelMode,
|
|
65
|
+
onlyRuleStyle,
|
|
66
|
+
label,
|
|
67
|
+
helpText,
|
|
68
|
+
extra,
|
|
69
|
+
errorLayout,
|
|
70
|
+
required,
|
|
71
|
+
showColon,
|
|
72
|
+
colSpan,
|
|
73
|
+
rowSpan,
|
|
74
|
+
children,
|
|
75
|
+
} = props;
|
|
76
|
+
return (
|
|
77
|
+
<LayoutFormItem
|
|
78
|
+
labelMode={labelMode}
|
|
79
|
+
onlyRuleStyle={onlyRuleStyle}
|
|
80
|
+
required={required}
|
|
81
|
+
label={label}
|
|
82
|
+
helpText={helpText}
|
|
83
|
+
extra={extra}
|
|
84
|
+
errorLayout={errorLayout}
|
|
85
|
+
showColon={showColon}
|
|
86
|
+
colSpan={colSpan}
|
|
87
|
+
rowSpan={rowSpan}
|
|
88
|
+
>
|
|
89
|
+
{children}
|
|
90
|
+
</LayoutFormItem>
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**隐藏表单项*/
|
|
95
|
+
export const FormHideItem = memo((props: FormItemProps) => {
|
|
96
|
+
const { name, sort, isJoinParentField } = props;
|
|
97
|
+
const { isHide } = useRegisterFormHideItem({ name, sort: sort, isJoinParentField });
|
|
98
|
+
if (isHide) {
|
|
99
|
+
return <Fragment />;
|
|
100
|
+
}
|
|
101
|
+
return <FormItemInstance {...props} />;
|
|
102
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RuleInstanceBase, FormItemInstanceBase, FormListInstanceBase } from '@carefrees/form-utils';
|
|
2
|
+
import React, { Fragment, memo } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
useRegisterFormHideItem,
|
|
5
|
+
FormItemParentNameProvider,
|
|
6
|
+
FormListInstanceContext,
|
|
7
|
+
useRegisterFormList,
|
|
8
|
+
RegisterFormListOptions,
|
|
9
|
+
} from '@carefrees/form-utils-react-hooks';
|
|
10
|
+
|
|
11
|
+
export interface FormListChildrenProps {
|
|
12
|
+
/**数据集合*/
|
|
13
|
+
fields: { name: number; key: number }[];
|
|
14
|
+
/**添加*/
|
|
15
|
+
onAdd: (initialValue?: Object) => void;
|
|
16
|
+
/**删除*/
|
|
17
|
+
onDelete: (index: number | number[]) => void;
|
|
18
|
+
/**移动*/
|
|
19
|
+
onMove: (from: number, to: number) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface FormListProps extends RegisterFormListOptions {
|
|
23
|
+
children: (
|
|
24
|
+
options: FormListChildrenProps,
|
|
25
|
+
instances: {
|
|
26
|
+
ruleInstance: RuleInstanceBase;
|
|
27
|
+
formItemInstance: FormItemInstanceBase;
|
|
28
|
+
formListInstance: FormListInstanceBase;
|
|
29
|
+
},
|
|
30
|
+
) => React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**form list 组件*/
|
|
34
|
+
export const FormList = memo((props: FormListProps) => {
|
|
35
|
+
const { children, ...rest } = props;
|
|
36
|
+
const { formListInstance, ruleInstance, formItemInstance } = useRegisterFormList(rest);
|
|
37
|
+
return (
|
|
38
|
+
<FormListInstanceContext.Provider value={formListInstance}>
|
|
39
|
+
<FormItemParentNameProvider name={formListInstance.name} sort={formListInstance.sort}>
|
|
40
|
+
{children(
|
|
41
|
+
{
|
|
42
|
+
fields: formListInstance.getFields(),
|
|
43
|
+
onAdd: formListInstance.onAdd,
|
|
44
|
+
onDelete: formListInstance.onDelete,
|
|
45
|
+
onMove: formListInstance.onMove,
|
|
46
|
+
},
|
|
47
|
+
{ ruleInstance, formItemInstance, formListInstance },
|
|
48
|
+
)}
|
|
49
|
+
</FormItemParentNameProvider>
|
|
50
|
+
</FormListInstanceContext.Provider>
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**隐藏 form list item 组件*/
|
|
55
|
+
export const FormHideList = memo((props: FormListProps) => {
|
|
56
|
+
const { name, sort, isJoinParentField } = props;
|
|
57
|
+
const { isHide } = useRegisterFormHideItem({ name, sort: sort, isJoinParentField });
|
|
58
|
+
if (isHide) {
|
|
59
|
+
return <Fragment />;
|
|
60
|
+
}
|
|
61
|
+
return <FormList {...props} />;
|
|
62
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { RuleInstanceBase, FormInstanceBase, FormItemInstanceBase, get } from '@carefrees/form-utils';
|
|
2
|
+
import { useRegisterFormItem, RegisterFormItemOptions, useHtmlFor } from '@carefrees/form-utils-react-hooks';
|
|
3
|
+
import React, { cloneElement, isValidElement, useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface FormItemAttrOptions extends RegisterFormItemOptions {
|
|
6
|
+
/**依赖更新项*/
|
|
7
|
+
dependencies?: string[];
|
|
8
|
+
/**通知 只用于校验规则提示 字段 */
|
|
9
|
+
noticeOnlyRuleDataField?: string[];
|
|
10
|
+
/**通知父级字段监听方法更新*/
|
|
11
|
+
isNoticeParentField?: boolean;
|
|
12
|
+
/**通知watch监听方法更新*/
|
|
13
|
+
noticeWatchField?: string[];
|
|
14
|
+
/**是否保护值(不进行表单项组件卸载重置初始值)*/
|
|
15
|
+
preserve?: boolean;
|
|
16
|
+
/**重写规则*/
|
|
17
|
+
useRules?: (ruleInstance: RuleInstanceBase, form: FormInstanceBase, formItemInstance: FormItemInstanceBase) => void;
|
|
18
|
+
/**输入框属性重写*/
|
|
19
|
+
useAttrs?: (attrs: any, form: FormInstanceBase, formItemInstance: FormItemInstanceBase) => any;
|
|
20
|
+
/**输入框属性*/
|
|
21
|
+
attrs?: any;
|
|
22
|
+
/**传递组件字段*/
|
|
23
|
+
valuePropName?: string;
|
|
24
|
+
/**取值字段(默认text)*/
|
|
25
|
+
getValuePath?: string;
|
|
26
|
+
/**自定义获取值*/
|
|
27
|
+
getValueFromEvent?: (event: any, form: FormInstanceBase, formItemInstance: FormItemInstanceBase) => any;
|
|
28
|
+
/**值格式化*/
|
|
29
|
+
formatValue?: (value: any, form: FormInstanceBase, formItemInstance: FormItemInstanceBase, event: any) => any;
|
|
30
|
+
/**触发数据更新之后触发(用于数据联动之类的)*/
|
|
31
|
+
onAfterUpdate?: (value: any, form: FormInstanceBase, formItemInstance: FormItemInstanceBase, event: any) => void;
|
|
32
|
+
/**事件名称*/
|
|
33
|
+
trigger?: string;
|
|
34
|
+
/**子元素*/
|
|
35
|
+
children?: React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**表单项参数*/
|
|
39
|
+
export const useFormItemAttr = (options: FormItemAttrOptions) => {
|
|
40
|
+
const {
|
|
41
|
+
trigger = 'onChange',
|
|
42
|
+
dependencies,
|
|
43
|
+
noticeOnlyRuleDataField,
|
|
44
|
+
isNoticeParentField,
|
|
45
|
+
noticeWatchField,
|
|
46
|
+
preserve,
|
|
47
|
+
valuePropName = 'value',
|
|
48
|
+
getValuePath = 'text',
|
|
49
|
+
getValueFromEvent,
|
|
50
|
+
formatValue,
|
|
51
|
+
onAfterUpdate,
|
|
52
|
+
useAttrs,
|
|
53
|
+
useRules,
|
|
54
|
+
attrs,
|
|
55
|
+
children,
|
|
56
|
+
...rest
|
|
57
|
+
} = options;
|
|
58
|
+
const { formItemInstance, form, ruleInstance, newName } = useRegisterFormItem({ ...rest });
|
|
59
|
+
formItemInstance.dependencies = dependencies;
|
|
60
|
+
formItemInstance.noticeOnlyRuleDataField = noticeOnlyRuleDataField;
|
|
61
|
+
formItemInstance.isNoticeParentField = isNoticeParentField;
|
|
62
|
+
formItemInstance.onAfterUpdate = onAfterUpdate;
|
|
63
|
+
formItemInstance.noticeWatchField = noticeWatchField;
|
|
64
|
+
formItemInstance.preserve = preserve;
|
|
65
|
+
|
|
66
|
+
/**获取值*/
|
|
67
|
+
const oldValue = form.getFieldValue(newName);
|
|
68
|
+
|
|
69
|
+
const onValueChange = (event: any) => {
|
|
70
|
+
try {
|
|
71
|
+
let value = event;
|
|
72
|
+
const target = event?.nativeEvent;
|
|
73
|
+
// event.nativeEvent.text
|
|
74
|
+
if (typeof getValueFromEvent === 'function') {
|
|
75
|
+
value = getValueFromEvent(event, form, formItemInstance);
|
|
76
|
+
} else if (event && target && typeof target === 'object' && getValuePath in target) {
|
|
77
|
+
value = get(target, getValuePath);
|
|
78
|
+
}
|
|
79
|
+
if (typeof formatValue === 'function') {
|
|
80
|
+
value = formatValue(value, form, formItemInstance, event);
|
|
81
|
+
}
|
|
82
|
+
if (oldValue !== value) {
|
|
83
|
+
form.updatedFieldValue(newName, value, 'validate');
|
|
84
|
+
formItemInstance.onAfterUpdate?.(value, form, formItemInstance, event);
|
|
85
|
+
if (Array.isArray(formItemInstance.noticeWatchField) && formItemInstance.noticeWatchField.length) {
|
|
86
|
+
form.noticeWatch(formItemInstance.noticeWatchField);
|
|
87
|
+
}
|
|
88
|
+
if (
|
|
89
|
+
Array.isArray(formItemInstance.noticeOnlyRuleDataField) &&
|
|
90
|
+
formItemInstance.noticeOnlyRuleDataField.length
|
|
91
|
+
) {
|
|
92
|
+
form.onlyValidate(formItemInstance.noticeOnlyRuleDataField);
|
|
93
|
+
}
|
|
94
|
+
if (formItemInstance.isNoticeParentField && formItemInstance.parentDataField) {
|
|
95
|
+
form.notice(formItemInstance.parentDataField);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log(error);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
formItemInstance.onChange = onValueChange;
|
|
103
|
+
|
|
104
|
+
// useHtmlFor
|
|
105
|
+
const htmlFor = useHtmlFor(newName);
|
|
106
|
+
formItemInstance.htmlFor = htmlFor;
|
|
107
|
+
|
|
108
|
+
const control: any = {
|
|
109
|
+
[trigger]: onValueChange,
|
|
110
|
+
...attrs,
|
|
111
|
+
name: newName,
|
|
112
|
+
id: htmlFor,
|
|
113
|
+
[valuePropName]: oldValue,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**触发数据调整*/
|
|
117
|
+
const newControl = useAttrs?.(control, form, formItemInstance) || control;
|
|
118
|
+
formItemInstance.control = newControl;
|
|
119
|
+
useRules?.(ruleInstance, form, formItemInstance);
|
|
120
|
+
const validateResult = useMemo(() => ruleInstance.getValidateResult(), [ruleInstance.messages]);
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
children: isValidElement(children) ? cloneElement(children, newControl) : children,
|
|
124
|
+
form,
|
|
125
|
+
formItemInstance,
|
|
126
|
+
ruleInstance,
|
|
127
|
+
onChange: onValueChange,
|
|
128
|
+
htmlFor,
|
|
129
|
+
validateResult,
|
|
130
|
+
};
|
|
131
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**公共属性*/
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
import { ViewProps } from 'react-native';
|
|
4
|
+
|
|
5
|
+
export interface AttrsOptions {
|
|
6
|
+
/**列数据*/
|
|
7
|
+
colCount?: number;
|
|
8
|
+
/**规则校验失败错误提示位置*/
|
|
9
|
+
errorLayout?: 'left-bottom' | 'right-bottom' | 'top-right' | 'top-left';
|
|
10
|
+
/**
|
|
11
|
+
* label显示模式
|
|
12
|
+
* @platform taro 支持 between
|
|
13
|
+
*/
|
|
14
|
+
labelMode?: 'left' | 'top' | 'between' | 'hide';
|
|
15
|
+
/**是否显示label后的冒号*/
|
|
16
|
+
showColon?: boolean;
|
|
17
|
+
/**表单项 className*/
|
|
18
|
+
formItemClassName?: string;
|
|
19
|
+
/**表单项 style*/
|
|
20
|
+
formItemStyle?: ViewProps['style'];
|
|
21
|
+
/**表单项 label className*/
|
|
22
|
+
formItemLabelClassName?: string;
|
|
23
|
+
/**表单项 label style*/
|
|
24
|
+
formItemLabelStyle?: ViewProps['style'];
|
|
25
|
+
/**
|
|
26
|
+
* 输入框底部边框
|
|
27
|
+
* @platform taro
|
|
28
|
+
*/
|
|
29
|
+
inputBordered?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**公共属性 Context */
|
|
33
|
+
export const AttrsContext = createContext<AttrsOptions>({
|
|
34
|
+
colCount: 1,
|
|
35
|
+
errorLayout: 'left-bottom',
|
|
36
|
+
labelMode: 'top',
|
|
37
|
+
showColon: true,
|
|
38
|
+
inputBordered: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**子项中获取公共属性*/
|
|
42
|
+
export const useAttrs = () => useContext(AttrsContext);
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React, { useMemo, useEffect } from 'react';
|
|
2
|
+
import { FormInstanceBase, ValidateErrorEntity } from '@carefrees/form-utils';
|
|
3
|
+
import { FormLayout, FormLayoutProps } from './layout';
|
|
4
|
+
import { ViewProps, View } from 'react-native';
|
|
5
|
+
import { useRegisterForm, useForm, FormInstanceContext } from '@carefrees/form-utils-react-hooks';
|
|
6
|
+
export * from './formItem';
|
|
7
|
+
export * from './formList';
|
|
8
|
+
export * from './layout';
|
|
9
|
+
export * from './layout/layout.formItem';
|
|
10
|
+
export * from './hooks/attr/attr.FormItem';
|
|
11
|
+
export * from '@carefrees/form-utils-react-hooks';
|
|
12
|
+
export { useAttrs, AttrsOptions, AttrsContext } from './hooks/useAttrs';
|
|
13
|
+
|
|
14
|
+
export interface FormProps<T = any> extends FormLayoutProps {
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
form?: FormInstanceBase;
|
|
17
|
+
style?: ViewProps['style'];
|
|
18
|
+
className?: string;
|
|
19
|
+
layoutClassName?: string;
|
|
20
|
+
layoutStyle?: ViewProps['style'];
|
|
21
|
+
/**表单数据*/
|
|
22
|
+
formData?: any;
|
|
23
|
+
/**值更新触发*/
|
|
24
|
+
onValuesChange?: (changedValues: Partial<T>, values: T) => void;
|
|
25
|
+
/**提交保存 验证成功*/
|
|
26
|
+
onFinish?: (values: T) => void;
|
|
27
|
+
/**提交保存 验证失败*/
|
|
28
|
+
onFinishFailed?: (errorInfo: ValidateErrorEntity<T>) => void;
|
|
29
|
+
/**隐藏表单项初始值*/
|
|
30
|
+
hideData?: Record<string, boolean>;
|
|
31
|
+
/**表单名称*/
|
|
32
|
+
name?: string;
|
|
33
|
+
/**隐藏规则校验*/
|
|
34
|
+
hideRuleData?: Record<string, boolean>;
|
|
35
|
+
/**自动重置更新formData数据*/
|
|
36
|
+
isAutoUpdatedFormData?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function Form<T = any>(props: FormProps<T>) {
|
|
40
|
+
const {
|
|
41
|
+
children,
|
|
42
|
+
form,
|
|
43
|
+
style,
|
|
44
|
+
className,
|
|
45
|
+
formData,
|
|
46
|
+
hideData,
|
|
47
|
+
hideRuleData,
|
|
48
|
+
isAutoUpdatedFormData = false,
|
|
49
|
+
name,
|
|
50
|
+
onFinish,
|
|
51
|
+
onFinishFailed,
|
|
52
|
+
onValuesChange,
|
|
53
|
+
layoutStyle,
|
|
54
|
+
layoutClassName,
|
|
55
|
+
...rest
|
|
56
|
+
} = props;
|
|
57
|
+
const formInstance = useForm(form);
|
|
58
|
+
useRegisterForm(formInstance, name);
|
|
59
|
+
useMemo(() => formInstance.ctor(formData, hideData, hideRuleData), []);
|
|
60
|
+
|
|
61
|
+
formInstance.onFinish = onFinish;
|
|
62
|
+
formInstance.onValuesChange = onValuesChange;
|
|
63
|
+
formInstance.onFinishFailed = onFinishFailed;
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (isAutoUpdatedFormData) {
|
|
67
|
+
formInstance.resetFormValues(formData);
|
|
68
|
+
}
|
|
69
|
+
}, [isAutoUpdatedFormData, formData]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<FormInstanceContext.Provider value={formInstance}>
|
|
73
|
+
<View style={style}>
|
|
74
|
+
<FormLayout {...rest} className={layoutClassName} style={layoutStyle}>
|
|
75
|
+
{children}
|
|
76
|
+
</FormLayout>
|
|
77
|
+
</View>
|
|
78
|
+
</FormInstanceContext.Provider>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React, { Fragment, useMemo, useRef, memo } from 'react';
|
|
2
|
+
import { AttrsOptions, useAttrs, AttrsContext } from './../hooks/useAttrs';
|
|
3
|
+
import { ViewProps, View, Text } from 'react-native';
|
|
4
|
+
import { StylesBase } from '../styles';
|
|
5
|
+
|
|
6
|
+
export interface FormLayoutProps extends AttrsOptions {
|
|
7
|
+
/**标题*/
|
|
8
|
+
title?: React.ReactNode;
|
|
9
|
+
/**额外内容*/
|
|
10
|
+
extra?: React.ReactNode;
|
|
11
|
+
/**内容*/
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
/**是否占据整行*/
|
|
14
|
+
isAllColSpan?: boolean;
|
|
15
|
+
className?: string;
|
|
16
|
+
/**头部ClassName*/
|
|
17
|
+
headerClassName?: string;
|
|
18
|
+
/**内容ClassName*/
|
|
19
|
+
bodyClassName?: string;
|
|
20
|
+
style?: ViewProps['style'];
|
|
21
|
+
/**头部样式*/
|
|
22
|
+
headerStyle?: ViewProps['style'];
|
|
23
|
+
/**内容样式*/
|
|
24
|
+
bodyStyle?: ViewProps['style'];
|
|
25
|
+
/**是否添加边框*/
|
|
26
|
+
bordered?: boolean;
|
|
27
|
+
/**列数据*/
|
|
28
|
+
colCount?: number;
|
|
29
|
+
/**
|
|
30
|
+
* @description gap 属性是用来设置网格行与列之间的间隙,该属性是row-gap and column-gap的简写形式。
|
|
31
|
+
*/
|
|
32
|
+
gap?: string | number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**布局组件*/
|
|
36
|
+
export const FormLayout = memo((props: FormLayoutProps) => {
|
|
37
|
+
const {
|
|
38
|
+
colCount: p_colCount = 4,
|
|
39
|
+
errorLayout: p_errorLayout = 'left-bottom',
|
|
40
|
+
labelMode: p_labelMode = 'left',
|
|
41
|
+
showColon: p_showColon = true,
|
|
42
|
+
formItemClassName: p_formItemClassName,
|
|
43
|
+
formItemStyle: p_formItemStyle,
|
|
44
|
+
formItemLabelClassName: p_formItemLabelClassName,
|
|
45
|
+
formItemLabelStyle: p_formItemLabelStyle,
|
|
46
|
+
} = useAttrs();
|
|
47
|
+
const {
|
|
48
|
+
colCount = p_colCount,
|
|
49
|
+
title,
|
|
50
|
+
extra,
|
|
51
|
+
children,
|
|
52
|
+
isAllColSpan,
|
|
53
|
+
className,
|
|
54
|
+
headerClassName,
|
|
55
|
+
bodyClassName,
|
|
56
|
+
style,
|
|
57
|
+
headerStyle,
|
|
58
|
+
bodyStyle,
|
|
59
|
+
errorLayout = p_errorLayout,
|
|
60
|
+
labelMode = p_labelMode,
|
|
61
|
+
showColon = p_showColon,
|
|
62
|
+
formItemClassName = p_formItemClassName,
|
|
63
|
+
formItemStyle = p_formItemStyle,
|
|
64
|
+
formItemLabelClassName = p_formItemLabelClassName,
|
|
65
|
+
formItemLabelStyle = p_formItemLabelStyle,
|
|
66
|
+
bordered = false,
|
|
67
|
+
gap,
|
|
68
|
+
} = props;
|
|
69
|
+
const propsRef = useRef(props);
|
|
70
|
+
propsRef.current = props;
|
|
71
|
+
|
|
72
|
+
const value = useMemo(() => {
|
|
73
|
+
return {
|
|
74
|
+
colCount,
|
|
75
|
+
errorLayout,
|
|
76
|
+
labelMode,
|
|
77
|
+
showColon,
|
|
78
|
+
formItemClassName,
|
|
79
|
+
formItemStyle,
|
|
80
|
+
formItemLabelClassName,
|
|
81
|
+
formItemLabelStyle,
|
|
82
|
+
};
|
|
83
|
+
}, [
|
|
84
|
+
colCount,
|
|
85
|
+
errorLayout,
|
|
86
|
+
labelMode,
|
|
87
|
+
showColon,
|
|
88
|
+
formItemClassName,
|
|
89
|
+
formItemStyle,
|
|
90
|
+
formItemLabelClassName,
|
|
91
|
+
formItemLabelStyle,
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
const styleBase = useMemo(() => {
|
|
95
|
+
const css: ViewProps['style'] = {};
|
|
96
|
+
if (typeof gap === 'string') {
|
|
97
|
+
css.gap = Number(gap);
|
|
98
|
+
}
|
|
99
|
+
if (typeof gap === 'number') {
|
|
100
|
+
css.gap = gap;
|
|
101
|
+
}
|
|
102
|
+
return css;
|
|
103
|
+
}, [colCount, gap]);
|
|
104
|
+
|
|
105
|
+
const layoutStyle = useMemo(() => {
|
|
106
|
+
return [
|
|
107
|
+
StylesBase['carefrees-form-layout'],
|
|
108
|
+
bordered && StylesBase['carefrees-form-layout.bordered'],
|
|
109
|
+
isAllColSpan && StylesBase.isAllColSpan,
|
|
110
|
+
style,
|
|
111
|
+
].filter(Boolean);
|
|
112
|
+
}, [bordered, isAllColSpan, style]);
|
|
113
|
+
|
|
114
|
+
const headStyle = useMemo(() => {
|
|
115
|
+
return [
|
|
116
|
+
StylesBase['carefrees-form-layout-header'],
|
|
117
|
+
bordered && StylesBase['carefrees-form-layout-header.bordered'],
|
|
118
|
+
headerStyle,
|
|
119
|
+
].filter(Boolean);
|
|
120
|
+
}, [bordered, headerStyle]);
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<AttrsContext.Provider value={value}>
|
|
124
|
+
<View style={layoutStyle}>
|
|
125
|
+
{title || extra ? (
|
|
126
|
+
<View style={headStyle}>
|
|
127
|
+
<View>
|
|
128
|
+
<Text style={[StylesBase['carefrees-form-layout-header-title']]}>{title}</Text>
|
|
129
|
+
</View>
|
|
130
|
+
<View>
|
|
131
|
+
<Text style={[StylesBase['carefrees-form-layout-header-extra']]}>{extra}</Text>
|
|
132
|
+
</View>
|
|
133
|
+
</View>
|
|
134
|
+
) : (
|
|
135
|
+
<Fragment />
|
|
136
|
+
)}
|
|
137
|
+
<View style={[StylesBase['carefrees-form-layout-body'], styleBase, bodyStyle]}>{children}</View>
|
|
138
|
+
</View>
|
|
139
|
+
</AttrsContext.Provider>
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
/**布局组件 占据一整行*/
|
|
144
|
+
export const FormLayoutRows = (props: ViewProps) => {
|
|
145
|
+
return <View {...props} style={[props.style, StylesBase.isAllColSpan]} />;
|
|
146
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { View, ViewProps, Text } from 'react-native';
|
|
2
|
+
import React, { Fragment, useMemo, memo } from 'react';
|
|
3
|
+
import { useAttrs } from '../hooks/useAttrs';
|
|
4
|
+
import { StylesBase } from '../styles';
|
|
5
|
+
|
|
6
|
+
export interface LayoutFormItemProps {
|
|
7
|
+
/**规则校验失败错误提示位置*/
|
|
8
|
+
errorLayout?: 'left-bottom' | 'right-bottom' | 'top-right' | 'top-left';
|
|
9
|
+
/**必填样式*/
|
|
10
|
+
required?: boolean;
|
|
11
|
+
/**label显示模式*/
|
|
12
|
+
labelMode?: 'left' | 'top' | 'between' | 'hide';
|
|
13
|
+
/**内容*/
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
/**只进行规则样式*/
|
|
16
|
+
onlyRuleStyle?: boolean;
|
|
17
|
+
label?: React.ReactNode;
|
|
18
|
+
/**底部提示内容*/
|
|
19
|
+
helpText?: React.ReactNode;
|
|
20
|
+
/**额外内容*/
|
|
21
|
+
extra?: React.ReactNode;
|
|
22
|
+
/**是否显示label后的冒号*/
|
|
23
|
+
showColon?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* 表单项占据列数
|
|
26
|
+
* @default 1
|
|
27
|
+
*/
|
|
28
|
+
colSpan?: number;
|
|
29
|
+
/**
|
|
30
|
+
* 表单项占据行数
|
|
31
|
+
* @default 1
|
|
32
|
+
*/
|
|
33
|
+
rowSpan?: number;
|
|
34
|
+
|
|
35
|
+
htmlFor?: string;
|
|
36
|
+
/**规则验证结果*/
|
|
37
|
+
validateResult?: {
|
|
38
|
+
tip: string | (string | undefined)[];
|
|
39
|
+
isInvalid: boolean;
|
|
40
|
+
};
|
|
41
|
+
// 样式部分
|
|
42
|
+
style?: ViewProps['style'];
|
|
43
|
+
className?: string;
|
|
44
|
+
labelStyle?: ViewProps['style'];
|
|
45
|
+
labelClassName?: string;
|
|
46
|
+
/**底部边框*/
|
|
47
|
+
inputBordered?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**布局组件 表单项*/
|
|
51
|
+
export const LayoutFormItem = memo((props: LayoutFormItemProps) => {
|
|
52
|
+
const {
|
|
53
|
+
formItemClassName,
|
|
54
|
+
formItemLabelClassName,
|
|
55
|
+
formItemLabelStyle,
|
|
56
|
+
formItemStyle,
|
|
57
|
+
labelMode: p_labelMode = 'top',
|
|
58
|
+
errorLayout: p_errorLayout = 'left-bottom',
|
|
59
|
+
showColon: p_showColon = true,
|
|
60
|
+
colCount = 1,
|
|
61
|
+
inputBordered: p_inputBordered = true,
|
|
62
|
+
} = useAttrs();
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
children,
|
|
66
|
+
labelMode = p_labelMode,
|
|
67
|
+
onlyRuleStyle,
|
|
68
|
+
label,
|
|
69
|
+
helpText,
|
|
70
|
+
extra,
|
|
71
|
+
showColon = p_showColon,
|
|
72
|
+
colSpan = 1,
|
|
73
|
+
validateResult,
|
|
74
|
+
htmlFor,
|
|
75
|
+
required,
|
|
76
|
+
errorLayout = p_errorLayout,
|
|
77
|
+
style,
|
|
78
|
+
className,
|
|
79
|
+
labelClassName,
|
|
80
|
+
labelStyle,
|
|
81
|
+
inputBordered = p_inputBordered,
|
|
82
|
+
} = props;
|
|
83
|
+
|
|
84
|
+
const tip = validateResult?.tip;
|
|
85
|
+
const isInvalid = !!validateResult?.isInvalid;
|
|
86
|
+
const _errorLayout = labelMode === 'between' ? 'right-bottom' : errorLayout;
|
|
87
|
+
const _isLabel = useMemo(() => label && labelMode !== 'hide', [label, labelMode]);
|
|
88
|
+
|
|
89
|
+
const _isShowColon = useMemo(() => {
|
|
90
|
+
return showColon && (labelMode === 'left' || labelMode === 'between');
|
|
91
|
+
}, [showColon, labelMode]);
|
|
92
|
+
|
|
93
|
+
const widthStyles: ViewProps['style'] = useMemo(() => {
|
|
94
|
+
if (colCount >= colSpan) {
|
|
95
|
+
return {
|
|
96
|
+
width: `${(100 / colCount) * colSpan}%`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return { width: `100%` };
|
|
100
|
+
}, [colSpan, colCount]);
|
|
101
|
+
|
|
102
|
+
const warpStyles = useMemo(() => {
|
|
103
|
+
return [
|
|
104
|
+
StylesBase['carefrees-form-item'],
|
|
105
|
+
onlyRuleStyle && StylesBase['carefrees-form-item.only-rule-style'],
|
|
106
|
+
widthStyles,
|
|
107
|
+
formItemStyle,
|
|
108
|
+
style,
|
|
109
|
+
].filter(Boolean);
|
|
110
|
+
}, [style, widthStyles, onlyRuleStyle, formItemStyle]);
|
|
111
|
+
|
|
112
|
+
const containerStyles = useMemo(() => {
|
|
113
|
+
return [
|
|
114
|
+
StylesBase['carefrees-form-item-container'],
|
|
115
|
+
labelMode === 'left' && StylesBase['carefrees-form-item-container.left'],
|
|
116
|
+
labelMode === 'between' && StylesBase['carefrees-form-item-container.between'],
|
|
117
|
+
].filter(Boolean);
|
|
118
|
+
}, [labelMode]);
|
|
119
|
+
|
|
120
|
+
const labelWarpStyles = useMemo(() => {
|
|
121
|
+
return [
|
|
122
|
+
StylesBase['carefrees-form-item-label-warp'],
|
|
123
|
+
labelMode === 'left' && StylesBase['carefrees-form-item-label-warp.left'],
|
|
124
|
+
(labelMode === 'left' || labelMode == 'between') && StylesBase['carefrees-form-item-label-warp.minHeight'],
|
|
125
|
+
formItemLabelStyle,
|
|
126
|
+
labelStyle,
|
|
127
|
+
].filter(Boolean);
|
|
128
|
+
}, [labelMode, labelStyle, formItemLabelStyle]);
|
|
129
|
+
|
|
130
|
+
const bodyStyles = useMemo(() => {
|
|
131
|
+
return [
|
|
132
|
+
StylesBase['carefrees-form-item-body'],
|
|
133
|
+
labelMode === 'between' && StylesBase['carefrees-form-item-body-com.between'],
|
|
134
|
+
].filter(Boolean);
|
|
135
|
+
}, [labelMode]);
|
|
136
|
+
|
|
137
|
+
const bodyInputStyles = useMemo(() => {
|
|
138
|
+
return [
|
|
139
|
+
StylesBase['carefrees-form-item-body-input'],
|
|
140
|
+
inputBordered && StylesBase['carefrees-form-item-body-input.input-bordered'],
|
|
141
|
+
labelMode === 'between' && StylesBase['carefrees-form-item-body-com.between'],
|
|
142
|
+
].filter(Boolean);
|
|
143
|
+
}, [labelMode, inputBordered]);
|
|
144
|
+
|
|
145
|
+
const errorStyles = useMemo(() => {
|
|
146
|
+
return [
|
|
147
|
+
StylesBase['carefrees-form-item-body-error'],
|
|
148
|
+
_errorLayout && StylesBase[`carefrees-form-item-body-error.${_errorLayout}`],
|
|
149
|
+
].filter(Boolean);
|
|
150
|
+
}, [_errorLayout]);
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<View style={warpStyles}>
|
|
154
|
+
<View style={containerStyles}>
|
|
155
|
+
{_isLabel ? (
|
|
156
|
+
<View style={labelWarpStyles}>
|
|
157
|
+
{required ? (
|
|
158
|
+
<View>
|
|
159
|
+
<Text style={[StylesBase.fontSize14, StylesBase['carefrees-form-item-label.required']]}>*</Text>
|
|
160
|
+
</View>
|
|
161
|
+
) : (
|
|
162
|
+
<Fragment />
|
|
163
|
+
)}
|
|
164
|
+
<View style={StylesBase['carefrees-form-item-label']}>
|
|
165
|
+
{typeof label === 'string' ? <Text style={StylesBase.fontSize14}>{label}</Text> : label}
|
|
166
|
+
</View>
|
|
167
|
+
{_isShowColon ? (
|
|
168
|
+
<View style={[StylesBase['carefrees-form-item-label.show-colon']]}>
|
|
169
|
+
<Text style={StylesBase.fontSize14}>:</Text>
|
|
170
|
+
</View>
|
|
171
|
+
) : (
|
|
172
|
+
<Fragment />
|
|
173
|
+
)}
|
|
174
|
+
</View>
|
|
175
|
+
) : (
|
|
176
|
+
<Fragment />
|
|
177
|
+
)}
|
|
178
|
+
<View style={bodyStyles}>
|
|
179
|
+
<View style={bodyInputStyles}>{children}</View>
|
|
180
|
+
{helpText ? (
|
|
181
|
+
<View style={StylesBase['carefrees-form-item-body-help']}>
|
|
182
|
+
{typeof helpText === 'string' ? <Text style={StylesBase.fontSize12}>{helpText}</Text> : helpText}
|
|
183
|
+
</View>
|
|
184
|
+
) : (
|
|
185
|
+
<Fragment />
|
|
186
|
+
)}
|
|
187
|
+
{isInvalid ? (
|
|
188
|
+
<View style={errorStyles}>
|
|
189
|
+
<Text style={StylesBase['error-text']}>{tip}</Text>
|
|
190
|
+
</View>
|
|
191
|
+
) : (
|
|
192
|
+
<Fragment />
|
|
193
|
+
)}
|
|
194
|
+
</View>
|
|
195
|
+
</View>
|
|
196
|
+
{extra ? (
|
|
197
|
+
<View style={StylesBase['carefrees-form-item-extra']}>
|
|
198
|
+
{typeof extra === 'string' ? <Text style={StylesBase.fontSize14}>{extra}</Text> : extra}
|
|
199
|
+
</View>
|
|
200
|
+
) : (
|
|
201
|
+
<Fragment />
|
|
202
|
+
)}
|
|
203
|
+
</View>
|
|
204
|
+
);
|
|
205
|
+
});
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export const StylesBase = StyleSheet.create({
|
|
4
|
+
'carefrees-form': {
|
|
5
|
+
fontSize: 14,
|
|
6
|
+
},
|
|
7
|
+
'carefrees-form-layout': {
|
|
8
|
+
width: '100%',
|
|
9
|
+
borderRadius: 4,
|
|
10
|
+
paddingBottom: 8,
|
|
11
|
+
position: 'relative',
|
|
12
|
+
},
|
|
13
|
+
'carefrees-form-layout.bordered': {
|
|
14
|
+
borderColor: '#e0e0e0',
|
|
15
|
+
borderWidth: 1,
|
|
16
|
+
borderStyle: 'solid',
|
|
17
|
+
},
|
|
18
|
+
'carefrees-form-layout-header': {
|
|
19
|
+
display: 'flex',
|
|
20
|
+
justifyContent: 'space-between',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
flexDirection: 'row',
|
|
23
|
+
borderBottomColor: '#e0e0e0',
|
|
24
|
+
borderBottomWidth: 1,
|
|
25
|
+
paddingTop: 5,
|
|
26
|
+
paddingBottom: 5,
|
|
27
|
+
marginBlockEnd: 4,
|
|
28
|
+
paddingInlineStart: 2,
|
|
29
|
+
paddingInlineEnd: 2,
|
|
30
|
+
},
|
|
31
|
+
'carefrees-form-layout-header.bordered': {
|
|
32
|
+
paddingInlineStart: 8,
|
|
33
|
+
paddingInlineEnd: 8,
|
|
34
|
+
},
|
|
35
|
+
isAllColSpan: {
|
|
36
|
+
width: '100%',
|
|
37
|
+
},
|
|
38
|
+
title: {
|
|
39
|
+
fontSize: 16,
|
|
40
|
+
fontWeight: 600,
|
|
41
|
+
color: '#1d2129',
|
|
42
|
+
},
|
|
43
|
+
'carefrees-form-layout-header-title': {
|
|
44
|
+
fontSize: 16,
|
|
45
|
+
fontWeight: 600,
|
|
46
|
+
color: '#1d2129',
|
|
47
|
+
},
|
|
48
|
+
extra: {
|
|
49
|
+
fontSize: 14,
|
|
50
|
+
fontWeight: 500,
|
|
51
|
+
color: '#1d2129',
|
|
52
|
+
},
|
|
53
|
+
'carefrees-form-layout-header-extra': {
|
|
54
|
+
fontSize: 14,
|
|
55
|
+
fontWeight: 500,
|
|
56
|
+
color: '#1d2129',
|
|
57
|
+
},
|
|
58
|
+
'carefrees-form-layout-body': {
|
|
59
|
+
width: '100%',
|
|
60
|
+
display: 'flex',
|
|
61
|
+
flexDirection: 'row',
|
|
62
|
+
flexWrap: 'wrap',
|
|
63
|
+
paddingInlineStart: 2,
|
|
64
|
+
paddingInlineEnd: 2,
|
|
65
|
+
gap: 2,
|
|
66
|
+
},
|
|
67
|
+
'carefrees-form-item': {
|
|
68
|
+
display: 'flex',
|
|
69
|
+
flexDirection: 'row',
|
|
70
|
+
alignItems: 'flex-start',
|
|
71
|
+
padding: 8,
|
|
72
|
+
color: 'rgba(0, 0, 0, 0.88)',
|
|
73
|
+
},
|
|
74
|
+
'carefrees-form-item.only-rule-style': {
|
|
75
|
+
padding: 0,
|
|
76
|
+
},
|
|
77
|
+
'carefrees-form-item-container': {
|
|
78
|
+
display: 'flex',
|
|
79
|
+
flexDirection: 'column',
|
|
80
|
+
gap: 4,
|
|
81
|
+
height: '100%',
|
|
82
|
+
flex: 1,
|
|
83
|
+
},
|
|
84
|
+
'carefrees-form-item-container.left': {
|
|
85
|
+
flexDirection: 'row',
|
|
86
|
+
gap: 8,
|
|
87
|
+
textAlign: 'left',
|
|
88
|
+
},
|
|
89
|
+
'carefrees-form-item-label-warp.left': {
|
|
90
|
+
justifyContent: 'flex-end',
|
|
91
|
+
},
|
|
92
|
+
'carefrees-form-item-container.between': {
|
|
93
|
+
gap: 8,
|
|
94
|
+
textAlign: 'left',
|
|
95
|
+
flexDirection: 'row',
|
|
96
|
+
justifyContent: 'space-between',
|
|
97
|
+
},
|
|
98
|
+
'carefrees-form-item-body-com.between': {
|
|
99
|
+
justifyContent: 'flex-end',
|
|
100
|
+
textAlign: 'right',
|
|
101
|
+
},
|
|
102
|
+
'carefrees-form-item-label-warp': {
|
|
103
|
+
display: 'flex',
|
|
104
|
+
flexDirection: 'row',
|
|
105
|
+
justifyContent: 'flex-start',
|
|
106
|
+
},
|
|
107
|
+
'carefrees-form-item-label-warp.minHeight': {
|
|
108
|
+
minHeight: 32,
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
},
|
|
111
|
+
'carefrees-form-item-label': {
|
|
112
|
+
display: 'flex',
|
|
113
|
+
alignItems: 'center',
|
|
114
|
+
justifyContent: 'flex-start',
|
|
115
|
+
position: 'relative',
|
|
116
|
+
fontSize: 14,
|
|
117
|
+
color: 'rgba(0, 0, 0, 0.88)',
|
|
118
|
+
},
|
|
119
|
+
'carefrees-form-item-label.show-colon': {
|
|
120
|
+
textAlign: 'center',
|
|
121
|
+
margin: 0,
|
|
122
|
+
marginInlineEnd: 2,
|
|
123
|
+
marginInlineStart: 2,
|
|
124
|
+
},
|
|
125
|
+
'carefrees-form-item-label.required': {
|
|
126
|
+
color: 'red',
|
|
127
|
+
margin: 0,
|
|
128
|
+
marginInlineEnd: 2,
|
|
129
|
+
},
|
|
130
|
+
'carefrees-form-item-body': {
|
|
131
|
+
position: 'relative',
|
|
132
|
+
display: 'flex',
|
|
133
|
+
flexDirection: 'column',
|
|
134
|
+
alignItems: 'flex-start',
|
|
135
|
+
justifyContent: 'flex-start',
|
|
136
|
+
gap: 4,
|
|
137
|
+
flex: 1,
|
|
138
|
+
},
|
|
139
|
+
'carefrees-form-item-body-input': {
|
|
140
|
+
width: '100%',
|
|
141
|
+
flex: 1,
|
|
142
|
+
display: 'flex',
|
|
143
|
+
justifyContent: 'flex-start',
|
|
144
|
+
alignItems: 'center',
|
|
145
|
+
flexDirection: 'row',
|
|
146
|
+
},
|
|
147
|
+
'carefrees-form-item-body-input.input-bordered': {
|
|
148
|
+
borderWidth: 0,
|
|
149
|
+
borderBottomColor: '#e0e0e0',
|
|
150
|
+
borderBottomWidth: 1,
|
|
151
|
+
borderStyle: 'solid',
|
|
152
|
+
},
|
|
153
|
+
'carefrees-form-item-body-help': {
|
|
154
|
+
width: '100%',
|
|
155
|
+
},
|
|
156
|
+
'carefrees-form-item-body-error': {
|
|
157
|
+
position: 'absolute',
|
|
158
|
+
width: '100%',
|
|
159
|
+
color: 'red',
|
|
160
|
+
top: 'auto',
|
|
161
|
+
left: 0,
|
|
162
|
+
right: 0,
|
|
163
|
+
bottom: -16,
|
|
164
|
+
paddingTop: 2,
|
|
165
|
+
zIndex: 10,
|
|
166
|
+
fontSize: 12,
|
|
167
|
+
display: 'flex',
|
|
168
|
+
flexDirection: 'row',
|
|
169
|
+
justifyContent: 'flex-start',
|
|
170
|
+
},
|
|
171
|
+
'error-text': {
|
|
172
|
+
fontSize: 12,
|
|
173
|
+
color: 'red',
|
|
174
|
+
},
|
|
175
|
+
'carefrees-form-item-body-error.right-bottom': {
|
|
176
|
+
top: 'auto',
|
|
177
|
+
left: 0,
|
|
178
|
+
right: 0,
|
|
179
|
+
bottom: -16,
|
|
180
|
+
justifyContent: 'flex-end',
|
|
181
|
+
},
|
|
182
|
+
'carefrees-form-item-body-error.top-left': {
|
|
183
|
+
top: -16,
|
|
184
|
+
left: 0,
|
|
185
|
+
right: 0,
|
|
186
|
+
bottom: 'auto',
|
|
187
|
+
justifyContent: 'flex-start',
|
|
188
|
+
},
|
|
189
|
+
'carefrees-form-item-body-error.top-right': {
|
|
190
|
+
top: -16,
|
|
191
|
+
left: 0,
|
|
192
|
+
right: 0,
|
|
193
|
+
bottom: 'auto',
|
|
194
|
+
justifyContent: 'flex-end',
|
|
195
|
+
},
|
|
196
|
+
'carefrees-form-item-extra': {},
|
|
197
|
+
fontSize12: {
|
|
198
|
+
fontSize: 12,
|
|
199
|
+
},
|
|
200
|
+
fontSize14: {
|
|
201
|
+
fontSize: 14,
|
|
202
|
+
},
|
|
203
|
+
});
|