feat: 表单label支持左右对齐方式 (#4311)

This commit is contained in:
RUNZE LU 2022-05-12 10:24:26 +08:00 committed by GitHub
parent e22e2f80ce
commit acc101b425
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 45 deletions

View File

@ -1068,29 +1068,30 @@ Table 类型的表单项,要实现服务端校验,可以使用 `路径key`
## 属性表 ## 属性表
| 属性名 | 类型 | 默认值 | 说明 | | 属性名 | 类型 | 默认值 | 说明 |
| -------------------- | -------------------------------------------------- | ------ | ---------------------------------------------------------- | | -------------------- | -------------------------------------------------- | --------- | ---------------------------------------------------------------- |
| type | `string` | | 指定表单项类型 | | type | `string` | | 指定表单项类型 |
| className | `string` | | 表单最外层类名 | | className | `string` | | 表单最外层类名 |
| inputClassName | `string` | | 表单控制器类名 | | inputClassName | `string` | | 表单控制器类名 |
| labelClassName | `string` | | label 的类名 | | labelClassName | `string` | | label 的类名 |
| name | `string` | | 字段名,指定该表单项提交时的 key | | name | `string` | | 字段名,指定该表单项提交时的 key |
| value | `string` | | 表单默认值 | | value | `string` | | 表单默认值 |
| label | [模板](../../../docs/concepts/template) 或 `false` | | 表单项标签 | | label | [模板](../../../docs/concepts/template) 或 `false` | | 表单项标签 |
| labelRemark | [Remark](../remark) | | 表单项标签描述 | | labelAlign | `"right" \| "left"` | `"right"` | 表单项标签对齐方式,默认右对齐,仅在 `mode`为`horizontal` 时生效 |
| description | [模板](../../../docs/concepts/template) | | 表单项描述 | | labelRemark | [Remark](../remark) | | 表单项标签描述 |
| placeholder | `string` | | 表单项描述 | | description | [模板](../../../docs/concepts/template) | | 表单项描述 |
| inline | `boolean` | | 是否为 内联 模式 | | placeholder | `string` | | 表单项描述 |
| submitOnChange | `boolean` | | 是否该表单项值发生变化时就提交当前表单。 | | inline | `boolean` | | 是否为 内联 模式 |
| disabled | `boolean` | | 当前表单项是否是禁用状态 | | submitOnChange | `boolean` | | 是否该表单项值发生变化时就提交当前表单。 |
| disabledOn | [表达式](../../../docs/concepts/expression) | | 当前表单项是否禁用的条件 | | disabled | `boolean` | | 当前表单项是否是禁用状态 |
| visible | [表达式](../../../docs/concepts/expression) | | 当前表单项是否禁用的条件 | | disabledOn | [表达式](../../../docs/concepts/expression) | | 当前表单项是否禁用的条件 |
| visibleOn | [表达式](../../../docs/concepts/expression) | | 当前表单项是否禁用的条件 | | visible | [表达式](../../../docs/concepts/expression) | | 当前表单项是否禁用的条件 |
| required | `boolean` | | 是否为必填。 | | visibleOn | [表达式](../../../docs/concepts/expression) | | 当前表单项是否禁用的条件 |
| requiredOn | [表达式](../../../docs/concepts/expression) | | 过[表达式](../Types.md#表达式)来配置当前表单项是否为必填。 | | required | `boolean` | | 是否为必填。 |
| validations | [表达式](../../../docs/concepts/expression) | | 表单项值格式验证,支持设置多个,多个规则用英文逗号隔开。 | | requiredOn | [表达式](../../../docs/concepts/expression) | | 过[表达式](../Types.md#表达式)来配置当前表单项是否为必填。 |
| validateApi | [表达式](../../../docs/types/api) | | 表单校验接口 | | validations | [表达式](../../../docs/concepts/expression) | | 表单项值格式验证,支持设置多个,多个规则用英文逗号隔开。 |
| autoUpdate | Object | | 自动填充配置 | | validateApi | [表达式](../../../docs/types/api) | | 表单校验接口 |
| autoUpdate.api | [api](../../types/api) | | 自动填充数据接口地址 | | autoUpdate | Object | | 自动填充配置 |
| autoUpdate.mapping | Object | | 自动填充字段映射关系 | | autoUpdate.api | [api](../../types/api) | | 自动填充数据接口地址 |
| autoUpdate.showToast | `boolean` | | 是否展示数据格式错误提示,默认为 false | | autoUpdate.mapping | Object | | 自动填充字段映射关系 |
| autoUpdate.showToast | `boolean` | | 是否展示数据格式错误提示,默认为 false |

View File

@ -170,6 +170,8 @@ order: 24
} }
``` ```
#### 两端对齐
有时表单内容需要两端对齐,可在 horizontal 中增加 justify 配置,注意只对内联控件生效 有时表单内容需要两端对齐,可在 horizontal 中增加 justify 配置,注意只对内联控件生效
```schema: scope="body" ```schema: scope="body"
@ -215,6 +217,34 @@ order: 24
} }
``` ```
#### label 对齐模式
水平模式下 `labelAlign` 可以设置标签文本的对齐方式,支持`right`和`left`,默认为`right`。该属性的优先级:表单项 > 表单。
```schema: scope="body"
{
"type": "form",
"title": "label对齐模式",
"mode": "horizontal",
"labelAlign": "left",
"body": [
{
"type": "input-email",
"name": "email",
"label": "邮箱",
"labelAlign": "right",
"required": true
},
{
"type": "input-password",
"name": "password",
"label": "密码",
"required": true
}
]
}
```
### 内联模式 ### 内联模式
使用内联模式展现表单项 使用内联模式展现表单项
@ -1160,6 +1190,7 @@ Form 支持轮询初始化接口,步骤如下:
| name | `string` | | 设置一个名字后,方便其他组件与其通信 | | name | `string` | | 设置一个名字后,方便其他组件与其通信 |
| mode | `string` | `normal` | 表单展示方式,可以是:`normal`、`horizontal` 或者 `inline` | | mode | `string` | `normal` | 表单展示方式,可以是:`normal`、`horizontal` 或者 `inline` |
| horizontal | `Object` | `{"left":"col-sm-2", "right":"col-sm-10", "offset":"col-sm-offset-2"}` | 当 mode 为 `horizontal` 时有用,用来控制 label | | horizontal | `Object` | `{"left":"col-sm-2", "right":"col-sm-10", "offset":"col-sm-offset-2"}` | 当 mode 为 `horizontal` 时有用,用来控制 label |
| labelAlign | `"right" \| "left"` | `"right"` | 表单项标签对齐方式,默认右对齐,仅在 `mode`为`horizontal` 时生效 |
| title | `string` | `"表单"` | Form 的标题 | | title | `string` | `"表单"` | Form 的标题 |
| submitText | `String` | `"提交"` | 默认的提交按钮名称,如果设置成空,则可以把默认按钮去掉。 | | submitText | `String` | `"提交"` | 默认的提交按钮名称,如果设置成空,则可以把默认按钮去掉。 |
| className | `string` | | 外层 Dom 的类名 | | className | `string` | | 外层 Dom 的类名 |
@ -1205,16 +1236,16 @@ Form 支持轮询初始化接口,步骤如下:
## 事件表 ## 事件表
| 事件名称 | 事件参数 | 说明 | | 事件名称 | 事件参数 | 说明 |
| --------------------- | ----------------------------- | -------------- | | --------------------- | ----------------------------------------------------------- | -------------- |
| inited | 表单数据 | 初始化完成 | | inited | 表单数据 | 初始化完成 |
| change | 表单数据 | 值变化 | | change | 表单数据 | 值变化 |
| formItemValidateSucc | 表单数据 | 表单项校验成功 | | formItemValidateSucc | 表单数据 | 表单项校验成功 |
| formItemValidateError | 表单数据 | 表单项校验失败 | | formItemValidateError | 表单数据 | 表单项校验失败 |
| validateSucc | 表单数据 | 表单校验成功 | | validateSucc | 表单数据 | 表单校验成功 |
| validateError | 表单数据 | 表单校验成功 | | validateError | 表单数据 | 表单校验成功 |
| submitSucc | 配置api时 `result: object` 接口返回内容; 否则为表单数据 | 提交成功 | | submitSucc | 配置 api 时: `result: object` 接口返回内容; 否则为表单数据 | 提交成功 |
| submitFail | `error: object` 接口返回内容 | 提交失败 | | submitFail | `error: object` 接口返回内容 | 提交失败 |
## 动作表 ## 动作表

View File

@ -420,7 +420,7 @@
@include input-clear(); @include input-clear();
} }
&-passwordReveal { &-revealPassword {
cursor: pointer; cursor: pointer;
color: var(--text--muted-color); color: var(--text--muted-color);
} }

View File

@ -119,6 +119,10 @@
> .#{$ns}Form-label { > .#{$ns}Form-label {
text-align: var(--Form--horizontal-label-align); text-align: var(--Form--horizontal-label-align);
white-space: var(--Form--horizontal-label-whiteSpace); white-space: var(--Form--horizontal-label-whiteSpace);
&--left {
text-align: left;
}
} }
} }

View File

@ -40,6 +40,8 @@ import debounce from 'lodash/debounce';
import {isEffectiveApi} from '../../utils/api'; import {isEffectiveApi} from '../../utils/api';
import {dataMapping} from '../../utils/tpl-builtin'; import {dataMapping} from '../../utils/tpl-builtin';
export type LabelAlign = 'right' | 'left';
export type FormControlSchemaAlias = SchemaObject; export type FormControlSchemaAlias = SchemaObject;
export interface FormBaseControl export interface FormBaseControl
@ -60,6 +62,11 @@ export interface FormBaseControl
*/ */
label?: string | false; label?: string | false;
/**
*
*/
labelAlign?: LabelAlign;
/** /**
* label className * label className
*/ */
@ -324,8 +331,10 @@ export interface FormItemProps extends RendererProps {
formInited: boolean; formInited: boolean;
formMode: 'normal' | 'horizontal' | 'inline' | 'row' | 'default'; formMode: 'normal' | 'horizontal' | 'inline' | 'row' | 'default';
formHorizontal: FormHorizontal; formHorizontal: FormHorizontal;
formLabelAlign: LabelAlign;
defaultSize?: 'xs' | 'sm' | 'md' | 'lg' | 'full'; defaultSize?: 'xs' | 'sm' | 'md' | 'lg' | 'full';
size?: 'xs' | 'sm' | 'md' | 'lg' | 'full'; size?: 'xs' | 'sm' | 'md' | 'lg' | 'full';
labelAlign?: LabelAlign;
disabled?: boolean; disabled?: boolean;
btnDisabled: boolean; btnDisabled: boolean;
defaultValue: any; defaultValue: any;
@ -605,6 +614,7 @@ export class FormItemWrap extends React.Component<FormItemProps> {
const horizontal = props.horizontal || props.formHorizontal || {}; const horizontal = props.horizontal || props.formHorizontal || {};
const left = getWidthRate(horizontal.left); const left = getWidthRate(horizontal.left);
const right = getWidthRate(horizontal.right); const right = getWidthRate(horizontal.right);
const labelAlign = props.labelAlign || props.formLabelAlign;
return ( return (
<div <div
@ -630,7 +640,8 @@ export class FormItemWrap extends React.Component<FormItemProps> {
? horizontal.leftFixed ? horizontal.leftFixed
: 'normal' : 'normal'
}`]: horizontal.leftFixed, }`]: horizontal.leftFixed,
[`Form-itemColumn--${left}`]: !horizontal.leftFixed [`Form-itemColumn--${left}`]: !horizontal.leftFixed,
'Form-label--left': labelAlign === 'left'
}, },
labelClassName labelClassName
)} )}

View File

@ -54,9 +54,9 @@ import {
SchemaReload SchemaReload
} from '../../Schema'; } from '../../Schema';
import {ActionSchema} from '../Action'; import {ActionSchema} from '../Action';
import {ButtonGroupControlSchema} from './ButtonGroupSelect';
import {DialogSchemaBase} from '../Dialog'; import {DialogSchemaBase} from '../Dialog';
import Alert from '../../components/Alert2';
import type {LabelAlign} from './Item';
export interface FormSchemaHorizontal { export interface FormSchemaHorizontal {
left?: number; left?: number;
@ -302,6 +302,11 @@ export interface FormSchema extends BaseSchema {
* *
*/ */
preventEnterSubmit?: boolean; preventEnterSubmit?: boolean;
/**
* label的对齐方式
*/
labelAlign?: LabelAlign;
} }
export type FormGroup = FormSchema & { export type FormGroup = FormSchema & {
@ -368,7 +373,8 @@ export default class Form extends React.Component<FormProps, object> {
}, },
wrapperComponent: '', wrapperComponent: '',
finishedField: 'finished', finishedField: 'finished',
initFinishedField: 'finished' initFinishedField: 'finished',
labelAlign: 'right'
}; };
static propsList: Array<string> = [ static propsList: Array<string> = [
'title', 'title',
@ -875,7 +881,10 @@ export default class Form extends React.Component<FormProps, object> {
if (!isAlive(store)) { if (!isAlive(store)) {
return; return;
} }
const dispatcher = await dispatchEvent('change', createObject(data, store.data)); const dispatcher = await dispatchEvent(
'change',
createObject(data, store.data)
);
if (!dispatcher?.prevented) { if (!dispatcher?.prevented) {
onChange && onChange &&
onChange( onChange(
@ -980,7 +989,10 @@ export default class Form extends React.Component<FormProps, object> {
if (Array.isArray(action.required) && action.required.length) { if (Array.isArray(action.required) && action.required.length) {
return store.validateFields(action.required).then(async result => { return store.validateFields(action.required).then(async result => {
if (!result) { if (!result) {
const dispatcher = await dispatchEvent('validateError', this.props.data); const dispatcher = await dispatchEvent(
'validateError',
this.props.data
);
if (!dispatcher?.prevented) { if (!dispatcher?.prevented) {
env.notify('error', __('Form.validateFailed')); env.notify('error', __('Form.validateFailed'));
} }
@ -1059,7 +1071,7 @@ export default class Form extends React.Component<FormProps, object> {
(ret: any) => ret && ret[finishedField || 'finished'], (ret: any) => ret && ret[finishedField || 'finished'],
cancel => (this.asyncCancel = cancel), cancel => (this.asyncCancel = cancel),
checkInterval checkInterval
) );
return { return {
cbResult, cbResult,
dispatcher dispatcher
@ -1456,7 +1468,8 @@ export default class Form extends React.Component<FormProps, object> {
resolveDefinitions, resolveDefinitions,
lazyChange, lazyChange,
formLazyChange, formLazyChange,
dispatchEvent dispatchEvent,
labelAlign
} = props; } = props;
const subProps = { const subProps = {
@ -1469,6 +1482,7 @@ export default class Form extends React.Component<FormProps, object> {
formSubmited: form.submited, formSubmited: form.submited,
formMode: mode, formMode: mode,
formHorizontal: horizontal, formHorizontal: horizontal,
formLabelAlign: labelAlign !== 'left' ? 'right' : labelAlign,
controlWidth, controlWidth,
disabled: disabled || (control as Schema).disabled || form.loading, disabled: disabled || (control as Schema).disabled || form.loading,
btnDisabled: disabled || form.loading || form.validating, btnDisabled: disabled || form.loading || form.validating,