From 5a263e681aa3a9400e179f0c10e664a54a1cb162 Mon Sep 17 00:00:00 2001 From: "guishu.zc" Date: Mon, 15 Feb 2021 02:06:39 +0800 Subject: [PATCH] feat: add formitem demo --- packages/antd/docs/components/FormItem.md | 172 ++++++++++++++++++++++ packages/antd/src/form-item/index.tsx | 98 +++++++++++- packages/antd/src/form-item/style.less | 127 ++++++++++++++++ packages/antd/src/form-item/style.ts | 3 +- 4 files changed, 397 insertions(+), 3 deletions(-) diff --git a/packages/antd/docs/components/FormItem.md b/packages/antd/docs/components/FormItem.md index e69de29bb2d..c71675fb643 100644 --- a/packages/antd/docs/components/FormItem.md +++ b/packages/antd/docs/components/FormItem.md @@ -0,0 +1,172 @@ +# FormItem + +> 表单字段组件,用于展示布局。 + +## Markup Schema 案例 + +```tsx +import React from 'react' +import { Form, Input as NextInput, Select } from 'antd'; +import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' +import { createForm } from '@formily/core' +import { FormProvider, createSchemaField } from '@formily/react' + +const SchemaField = createSchemaField({ + components: { + Input, + Select, + FormItem, + }, +}) + +const form = createForm() + +export default () => ( + + + + + + + 提交 + + + + + +) +``` + +## JOSN Schema 案例 + +```tsx +import React from 'react' +import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' +import { createForm } from '@formily/core' +import { FormProvider, createSchemaField } from '@formily/react' + +const SchemaField = createSchemaField({ + components: { + Input, + FormItem, + }, +}) + +const form = createForm() + +const schema = { + type: 'object', + properties: { + input: { + type: 'string', + title: '输入框', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + 'x-component-props': { + style: { + width: 240, + }, + }, + }, + }, +} + +export default () => ( + + + + 提交 + + +) +``` + +## 纯 JSX 案例 + +```tsx +import React from 'react' +import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' +import { createForm } from '@formily/core' +import { FormProvider, Field } from '@formily/react' + +const form = createForm() + +export default () => ( + + + + 提交 + + +) +``` + +## API + +### FormItem + +| 属性名 | 类型 | 描述 | 默认值 | +| ------ | ------ | ---------- | ------ | +| colon | boolean | 冒号 | true | +| tooltip | ReactNode | 问号提示 | - | +| labelAlign | `"left"` \| `"right"` | 标签文本对齐方式 | `"right"` | +| labelWrap | boolean | 标签换⾏,否则出现省略号,hover有tooltip | false | +| labelWidth | number | 标签固定宽度 | - | +| wrapperWidth | number | 内容固定宽度 | - | +| labelCol | number | 标签⽹格所占列数,和内容列数加起来总和为24 | - | +| wrapperCol | number | 内容⽹格所占列数,和标签列数加起来总和为24 | - | +| wrapperAlign | `"left"` \| `"right"` | 内容文本对齐方式⻬ | `"left"` | +| wrapperWrap | boolean | 内容换⾏,否则出现省略号,hover有tooltip | false | +| fullness | boolean | 内容撑满 | false | +| addonBefore | ReactNode | 前缀内容 | - | +| addonAfter | ReactNode | 后缀内容 | - | +| size | `"small"` \| `"default"` \| `"large"` | 尺⼨ | - | +| inset | boolean | 是否是内嵌布局 | false | +| extra | ReactNode | 扩展描述⽂案 | - | +| feedbackText | ReactNode | 反馈⽂案 | - | +| feedbackLayout | `"loose"` \| `"terse"` \| `"popover"` | 反馈布局 | - | +| feedbackStatus | `"error"` \| `"warning"` \| `"success"` \| `"pending"` | 反馈布局 | - | +| feedbackIcon | ReactNode | 反馈图标 | - | +| asterisk | boolean | 星号提醒 | - | +| gridSpan | number | ⽹格布局占宽 | - | +| bordered | boolean | 是否有边框 | - | + diff --git a/packages/antd/src/form-item/index.tsx b/packages/antd/src/form-item/index.tsx index 1cd147de2aa..f0e164ae896 100644 --- a/packages/antd/src/form-item/index.tsx +++ b/packages/antd/src/form-item/index.tsx @@ -1,13 +1,100 @@ -import { Form } from 'antd' +import React from 'react' +import cls from 'classnames' +import { usePrefixCls } from '../__builtins__' import { isVoidField } from '@formily/core' import { connect, mapProps } from '@formily/react' +import { useFormLayout, useFormShallowLayout } from '../form-layout' + +const useFormItemLayout = (props) => { + const shallowFormLayout = useFormShallowLayout(); + const formLayout = useFormLayout(); + const layout = shallowFormLayout || formLayout || {}; + + return { + ...props, + colon: props.colon || layout.colon, + labelAlign: props.labelAlign || layout.labelAlign, + labelWrap: props.labelWrap || layout.labelWrap, + labelWidth: props.labelWidth || layout.labelWidth, + wrapperWidth: props.wrapperWidth || layout.wrapperWidth, + labelCol: props.labelCol || layout.labelCol, + wrapperCol: props.wrapperCol || layout.wrapperCol, + wrapperAlign: props.wrapperAlign || layout.wrapperAlign, + wrapperWrap: props.wrapperWrap || layout.wrapperWrap, + fullness: props.fullness || layout.fullness, + size: props.size || layout.size, + inset: props.inset || layout.inset, + asterisk: props.asterisk || layout.asterisk, + bordered: props.bordered || layout.bordered, + feedbackIcon: props.feedbackIcon || layout.feedbackIcon, + } +} + +export const FormItemBase = (props) => { + const { children, ...others } = props; + const formLayout = useFormItemLayout(others); + const { label, colon = true, addonBefore, asterisk, feedbackStatus, extra, help, + fullness, feedbackLayout, + labelWidth, wrapperWidth, labelCol, wrapperCol, + labelAlign = 'right', wrapperAlign = 'left', + size, labelWrap, wrapperWrap, + } = formLayout; + const labelStyle: any = {}; + const wrapperStyle: any = {}; + + // 固定宽度 + let enableCol = false; + if (labelWidth || wrapperWidth) { + if (labelWidth) { + labelStyle.width = `${labelWidth}px`; + } + if (wrapperWidth) { + wrapperStyle.width = `${wrapperWidth}px`; + } + // 栅格模式 + } else if (labelCol || wrapperCol) { + enableCol = true; + } + + const prefixCls = usePrefixCls('formily-form-item', props) + return
+
+ { asterisk && {'*'}} + {label} + { colon && {':'} } +
+
+
+ {addonBefore &&
{addonBefore}
} +
{children}
+ {addonBefore &&
{addonBefore}
} +
+ {help &&
{help}
} + {extra &&
{extra}
} +
+
+} export const FormItem = connect( - Form.Item, + FormItemBase, mapProps( { extract: 'validateStatus' }, { extract: 'title', to: 'label' }, { extract: 'required' }, + { extract: 'required', to: 'asterisk' }, (props, field) => { if (!field) return props if (isVoidField(field)) return props @@ -20,6 +107,13 @@ export const FormItem = connect( help: field.description, } } + }, + (props, field) => { + if (!field.feedbackStatus && field.validateStatus) { + return { + feedbackStatus: field.validateStatus, + } + } } ) ) diff --git a/packages/antd/src/form-item/style.less b/packages/antd/src/form-item/style.less index e69de29bb2d..8cb7af3e6a4 100644 --- a/packages/antd/src/form-item/style.less +++ b/packages/antd/src/form-item/style.less @@ -0,0 +1,127 @@ +@import '~antd/lib/style/themes/default.less'; + +@form-item-cls: ~'@{ant-prefix}-formily-form-item'; + +.@{form-item-cls} { + display: flex; +} + +.@{form-item-cls}-label { + flex: initial; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.@{form-item-cls}-label-align-left { + .@{form-item-cls}-label { + text-align: left; + } +} +.@{form-item-cls}-label-align-right { + .@{form-item-cls}-label { + text-align: right; + } +} + +.@{form-item-cls}-label-wrap { + .@{form-item-cls}-label { + white-space: pre-line; + } +} + +.@{form-item-cls}-control { + + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + .@{form-item-cls}-control-content { + display: flex; + + .@{form-item-cls}-control-content-component { + flex: 1; + } + + .@{form-item-cls}-addon-before { + margin-right: 8px; + } + .@{form-item-cls}-addon-after { + margin-left: 8px; + } + } +} +.@{form-item-cls}-control-align-left { + .@{form-item-cls}-control { + text-align: left; + } +} +.@{form-item-cls}-control-align-right { + .@{form-item-cls}-control { + text-align: right; + } +} +.@{form-item-cls}-control-wrap { + .@{form-item-cls}-control { + white-space: pre-line; + } +} + +.@{form-item-cls}-asterisk { + color: #ff4d4f; + margin-right: 4px; + line-height: 1; + display: inline-block; + font-family: SimSun,sans-serif; +} +.@{form-item-cls}-colon { + margin-left: 2px; + margin-right: 8px; +} + +.@{form-item-cls}-help, +.@{form-item-cls}-extra { + clear: both; + min-height: 24px; + color: rgba(0, 0, 0, 0.45); + font-size: 14px; + line-height: 1.5715; + transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1); + padding-top: 0px; +} + +.@{form-item-cls}-fullness { + > .@{form-item-cls}-control { + > .@{form-item-cls}-control-content { + > .@{form-item-cls}-control-content-component { + > * { + width: 100%; + } + } + } + } +} + +.@{form-item-cls}-error { + .ant-input, + .ant-input-affix-wrapper, + .ant-input-affix-wrapper:hover, + .ant-input:hover { + background-color: #fff; + border-color: #ff4d4f; + } + + .ant-input-affix-wrapper-focused, + .ant-input-affix-wrapper:focus, + .ant-input-focused, + .ant-input:focus { + border-color: #ff7875; + border-right-width: 1px!important; + outline: 0; + box-shadow: 0 0 0 2px #ff4d4f33; + } + + .@{form-item-cls}-help { + color: #ff4d4f; + } +} \ No newline at end of file diff --git a/packages/antd/src/form-item/style.ts b/packages/antd/src/form-item/style.ts index 6c4932cfffd..dd1ffc5c8ac 100644 --- a/packages/antd/src/form-item/style.ts +++ b/packages/antd/src/form-item/style.ts @@ -1 +1,2 @@ -import 'antd/lib/form/style/index' \ No newline at end of file +import 'antd/lib/form/style/index' +import './style.less'