(value: T[]): T[] {
+ const [cacheValue, setCacheValue] = React.useState(value);
+ React.useEffect(() => {
+ const timeout = setTimeout(
+ () => {
+ setCacheValue(value);
+ },
+ value.length ? 0 : 10,
+ );
+
+ return () => {
+ clearTimeout(timeout);
+ };
+ }, [value]);
+
+ return cacheValue;
+}
diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md
index 707cf03508..06f8b73a2d 100644
--- a/components/form/index.en-US.md
+++ b/components/form/index.en-US.md
@@ -302,22 +302,23 @@ Rule supports a config object, or a function returning config object:
type Rule = RuleConfig | ((form: FormInstance) => RuleConfig);
```
-| Name | Description | Type |
-| --- | --- | --- |
-| defaultField | Validate rule for all array elements, valid when `type` is `array` | [rule](#Rule) |
-| enum | Match enum value. You need to set `type` to `enum` to enable this | any\[] |
-| fields | Validate rule for child elements, valid when `type` is `array` or `object` | Record<string, [rule](#Rule)> |
-| len | Length of string, number, array | number |
-| max | `type` required: max length of `string`, `number`, `array` | number |
-| message | Error message. Will auto generate by [template](#validateMessages) if not provided | string |
-| min | `type` required: min length of `string`, `number`, `array` | number |
-| pattern | Regex pattern | RegExp |
-| required | Required field | boolean |
-| transform | Transform value to the rule before validation | (value) => any |
-| type | Normally `string` \|`number` \|`boolean` \|`url` \| `email`. More type to ref [here](https://github.com/yiminghe/async-validator#type) | string |
-| validateTrigger | Set validate trigger event. Must be the sub set of `validateTrigger` in Form.Item | string \| string\[] |
-| validator | Customize validation rule. Accept Promise as return. See [example](#components-form-demo-register) | ([rule](#Rule), value) => Promise |
-| whitespace | Failed if only has whitespace | boolean |
+| Name | Description | Type | Version |
+| --- | --- | --- | --- |
+| defaultField | Validate rule for all array elements, valid when `type` is `array` | [rule](#Rule) | |
+| enum | Match enum value. You need to set `type` to `enum` to enable this | any\[] | |
+| fields | Validate rule for child elements, valid when `type` is `array` or `object` | Record<string, [rule](#Rule)> | |
+| len | Length of string, number, array | number | |
+| max | `type` required: max length of `string`, `number`, `array` | number | |
+| message | Error message. Will auto generate by [template](#validateMessages) if not provided | string | |
+| min | `type` required: min length of `string`, `number`, `array` | number | |
+| pattern | Regex pattern | RegExp | |
+| required | Required field | boolean | |
+| transform | Transform value to the rule before validation | (value) => any | |
+| type | Normally `string` \|`number` \|`boolean` \|`url` \| `email`. More type to ref [here](https://github.com/yiminghe/async-validator#type) | string | |
+| validateTrigger | Set validate trigger event. Must be the sub set of `validateTrigger` in Form.Item | string \| string\[] | |
+| validator | Customize validation rule. Accept Promise as return. See [example](#components-form-demo-register) | ([rule](#Rule), value) => Promise | |
+| warningOnly | Warning only. Not block form submit | boolean | 4.17.0 |
+| whitespace | Failed if only has whitespace | boolean | |
## Migrate to v4
diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md
index ae0c514c7e..c1234496f6 100644
--- a/components/form/index.zh-CN.md
+++ b/components/form/index.zh-CN.md
@@ -301,22 +301,23 @@ Rule 支持接收 object 进行配置,也支持 function 来动态获取 form
type Rule = RuleConfig | ((form: FormInstance) => RuleConfig);
```
-| 名称 | 说明 | 类型 |
-| --- | --- | --- |
-| defaultField | 仅在 `type` 为 `array` 类型时有效,用于指定数组元素的校验规则 | [rule](#Rule) |
-| enum | 是否匹配枚举中的值(需要将 `type` 设置为 `enum`) | any\[] |
-| fields | 仅在 `type` 为 `array` 或 `object` 类型时有效,用于指定子元素的校验规则 | Record<string, [rule](#Rule)> |
-| len | string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度 | number |
-| max | 必须设置 `type`:string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度 | number |
-| message | 错误信息,不设置时会通过[模板](#validateMessages)自动生成 | string |
-| min | 必须设置 `type`:string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度 | number |
-| pattern | 正则表达式匹配 | RegExp |
-| required | 是否为必选字段 | boolean |
-| transform | 将字段值转换成目标值后进行校验 | (value) => any |
-| type | 类型,常见有 `string` \|`number` \|`boolean` \|`url` \| `email`。更多请参考[此处](https://github.com/yiminghe/async-validator#type) | string |
-| validateTrigger | 设置触发验证时机,必须是 Form.Item 的 `validateTrigger` 的子集 | string \| string\[] |
-| validator | 自定义校验,接收 Promise 作为返回值。[示例](#components-form-demo-register)参考 | ([rule](#Rule), value) => Promise |
-| whitespace | 如果字段仅包含空格则校验不通过 | boolean |
+| 名称 | 说明 | 类型 | 版本 |
+| --- | --- | --- | --- |
+| defaultField | 仅在 `type` 为 `array` 类型时有效,用于指定数组元素的校验规则 | [rule](#Rule) | |
+| enum | 是否匹配枚举中的值(需要将 `type` 设置为 `enum`) | any\[] | |
+| fields | 仅在 `type` 为 `array` 或 `object` 类型时有效,用于指定子元素的校验规则 | Record<string, [rule](#Rule)> | |
+| len | string 类型时为字符串长度;number 类型时为确定数字; array 类型时为数组长度 | number | |
+| max | 必须设置 `type`:string 类型为字符串最大长度;number 类型时为最大值;array 类型时为数组最大长度 | number | |
+| message | 错误信息,不设置时会通过[模板](#validateMessages)自动生成 | string | |
+| min | 必须设置 `type`:string 类型为字符串最小长度;number 类型时为最小值;array 类型时为数组最小长度 | number | |
+| pattern | 正则表达式匹配 | RegExp | |
+| required | 是否为必选字段 | boolean | |
+| transform | 将字段值转换成目标值后进行校验 | (value) => any | |
+| type | 类型,常见有 `string` \|`number` \|`boolean` \|`url` \| `email`。更多请参考[此处](https://github.com/yiminghe/async-validator#type) | string | |
+| validateTrigger | 设置触发验证时机,必须是 Form.Item 的 `validateTrigger` 的子集 | string \| string\[] | |
+| validator | 自定义校验,接收 Promise 作为返回值。[示例](#components-form-demo-register)参考 | ([rule](#Rule), value) => Promise | |
+| warningOnly | 仅警告,不阻塞表单提交 | boolean | 4.17.0 |
+| whitespace | 如果字段仅包含空格则校验不通过 | boolean | |
## 从 v3 升级到 v4
diff --git a/components/form/style/index.less b/components/form/style/index.less
index 5ea9f43c2f..70834511b7 100644
--- a/components/form/style/index.less
+++ b/components/form/style/index.less
@@ -61,9 +61,12 @@
margin-bottom: @form-item-margin-bottom;
vertical-align: top;
+ // We delay one frame (0.017s) here to let CSSMotion goes
+ transition: margin-bottom @animation-duration-slow 0.017s linear;
&-with-help {
margin-bottom: 0;
+ transition: none;
}
&-hidden,
@@ -89,7 +92,6 @@
> label {
position: relative;
- // display: inline;
display: inline-flex;
align-items: center;
height: @form-item-label-height;
@@ -179,10 +181,12 @@
}
}
+ // ==============================================================
+ // = Explain =
+ // ==============================================================
&-explain,
&-extra {
clear: both;
- min-height: @form-item-margin-bottom;
color: @text-color-secondary;
font-size: @font-size-base;
line-height: @line-height-base;
@@ -190,43 +194,64 @@
.explainAndExtraDistance((@form-item-margin-bottom - @form-font-height) / 2);
}
+ &-explain {
+ height: 0;
+ min-height: 0;
+ opacity: 0;
+ }
+
+ &-extra {
+ min-height: @form-item-margin-bottom;
+ }
+
.@{ant-prefix}-input-textarea-show-count {
&::after {
margin-bottom: -22px;
}
}
-}
-.show-help-motion(@className, @keyframeName, @duration: @animation-duration-slow) {
- @name: ~'@{ant-prefix}-@{className}';
- .make-motion(@name, @keyframeName, @duration);
- .@{name}-enter,
- .@{name}-appear {
- opacity: 0;
- animation-timing-function: @ease-in-out;
- }
- .@{name}-leave {
- animation-timing-function: @ease-in-out;
- }
-}
-
-.show-help-motion(show-help, antShowHelp, 0.3s);
-
-@keyframes antShowHelpIn {
- 0% {
- transform: translateY(-5px);
- opacity: 0;
- }
- 100% {
- transform: translateY(0);
+ &-with-help &-explain {
+ height: auto;
+ min-height: @form-item-margin-bottom;
opacity: 1;
}
}
-@keyframes antShowHelpOut {
- to {
+// >>>>>>>>>> Motion <<<<<<<<<<
+// Explain holder
+.@{ant-prefix}-show-help {
+ transition: height @animation-duration-slow linear, min-height @animation-duration-slow linear,
+ margin-bottom @animation-duration-slow @ease-in-out,
+ opacity @animation-duration-slow @ease-in-out;
+
+ &-leave {
+ min-height: @form-item-margin-bottom;
+
+ &-active {
+ min-height: 0;
+ }
+ }
+}
+
+// Explain
+.@{ant-prefix}-show-help-item {
+ overflow: hidden;
+ transition: height @animation-duration-slow @ease-in-out,
+ opacity @animation-duration-slow @ease-in-out, transform @animation-duration-slow @ease-in-out !important;
+
+ &-appear,
+ &-enter {
transform: translateY(-5px);
opacity: 0;
+
+ &-active {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ }
+
+ &-leave-active {
+ transform: translateY(-5px);
}
}
diff --git a/components/form/style/status.less b/components/form/style/status.less
index 75add0b1bb..fe47549e65 100644
--- a/components/form/style/status.less
+++ b/components/form/style/status.less
@@ -9,11 +9,11 @@
// ========================= Explain =========================
/* To support leave along ErrorList. We add additional className to handle explain style */
&-explain {
- &&-error {
+ &-error {
color: @error-color;
}
- &&-warning {
+ &-warning {
color: @warning-color;
}
}
diff --git a/components/table/__tests__/__snapshots__/demo.test.js.snap b/components/table/__tests__/__snapshots__/demo.test.js.snap
index 75e8064f92..67de1cfcc0 100644
--- a/components/table/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/table/__tests__/__snapshots__/demo.test.js.snap
@@ -16705,7 +16705,21 @@ exports[`renders ./components/table/demo/sticky.md correctly 1`] = `
colspan="2"
style="position:sticky;left:0"
>
- Fix Left
+
(
-
-
-
- Fix Left
-
-
- Scroll Context
-
- Fix Right
-
-
- )}
- sticky
- />,
- mountNode,
-);
+const Demo = () => {
+ const [fixedTop, setFixedTop] = React.useState(false);
+
+ return (
+ (
+
+
+
+ {
+ setFixedTop(!fixedTop);
+ }}
+ />
+
+
+ Scroll Context
+
+ Fix Right
+
+
+ )}
+ sticky
+ />
+ );
+};
+
+ReactDOM.render(, mountNode);
```
diff --git a/components/tree-select/__tests__/__snapshots__/demo.test.js.snap b/components/tree-select/__tests__/__snapshots__/demo.test.js.snap
index ec3fd447e2..ed526d3ef8 100644
--- a/components/tree-select/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/tree-select/__tests__/__snapshots__/demo.test.js.snap
@@ -381,3 +381,111 @@ exports[`renders ./components/tree-select/demo/treeData.md correctly 1`] = `
`;
+
+exports[`renders ./components/tree-select/demo/treeLine.md correctly 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/components/tree-select/demo/async.md b/components/tree-select/demo/async.md
index a670e59694..b9db90f5c5 100644
--- a/components/tree-select/demo/async.md
+++ b/components/tree-select/demo/async.md
@@ -45,6 +45,7 @@ class Demo extends React.Component {
treeData: this.state.treeData.concat([
this.genTreeNode(id, false),
this.genTreeNode(id, true),
+ this.genTreeNode(id, true),
]),
});
resolve();
diff --git a/components/tree-select/demo/treeLine.md b/components/tree-select/demo/treeLine.md
new file mode 100644
index 0000000000..dfbf7dac6f
--- /dev/null
+++ b/components/tree-select/demo/treeLine.md
@@ -0,0 +1,56 @@
+---
+order: 6
+title:
+ zh-CN: 线性样式
+ en-US: Show Tree Line
+---
+
+## zh-CN
+
+通过 `treeLine` 配置线性样式。
+
+## en-US
+
+Use `treeLine` to show the line style.
+
+```tsx
+import { TreeSelect, Switch, Space } from 'antd';
+
+const { TreeNode } = TreeSelect;
+
+const Demo = () => {
+ const [treeLine, setTreeLine] = React.useState(true);
+ const [showLeafIcon, setShowLeafIcon] = React.useState(false);
+
+ return (
+
+ setTreeLine(!treeLine)}
+ />
+ setShowLeafIcon(!showLeafIcon)}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+ReactDOM.render(, mountNode);
+```
diff --git a/components/tree-select/index.en-US.md b/components/tree-select/index.en-US.md
index 480b48634e..7fe711cef6 100644
--- a/components/tree-select/index.en-US.md
+++ b/components/tree-select/index.en-US.md
@@ -50,6 +50,7 @@ Tree selection control.
| treeDefaultExpandedKeys | Default expanded treeNodes | string\[] | - | |
| treeExpandedKeys | Set expanded keys | string\[] | - | |
| treeIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false | |
+| treeLine | Show the line. Ref [Tree - showLine](/components/tree/#components-tree-demo-line) | boolean \| object | false | 4.17.0 |
| treeNodeFilterProp | Will be used for filtering if `filterTreeNode` returns true | string | `value` | |
| treeNodeLabelProp | Will render as content of select | string | `title` | |
| value | To set the current selected treeNode(s) | string \| string\[] | - | |
@@ -62,10 +63,10 @@ Tree selection control.
### Tree Methods
-| Name | Description | Version |
-| --- | --- | --- |
-| blur() | Remove focus | |
-| focus() | Get focus | |
+| Name | Description | Version |
+| ------- | ------------ | ------- |
+| blur() | Remove focus | |
+| focus() | Get focus | |
### TreeNode props
diff --git a/components/tree-select/index.tsx b/components/tree-select/index.tsx
index de31c68179..2ed5c9471b 100644
--- a/components/tree-select/index.tsx
+++ b/components/tree-select/index.tsx
@@ -11,7 +11,7 @@ import omit from 'rc-util/lib/omit';
import { DefaultValueType } from 'rc-tree-select/lib/interface';
import { ConfigContext } from '../config-provider';
import devWarning from '../_util/devWarning';
-import { AntTreeNodeProps } from '../tree';
+import { AntTreeNodeProps, TreeProps } from '../tree';
import getIcons from '../select/utils/iconUtil';
import renderSwitcherIcon from '../tree/utils/iconUtil';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
@@ -30,11 +30,18 @@ export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[];
export interface TreeSelectProps
extends Omit<
RcTreeSelectProps,
- 'showTreeIcon' | 'treeMotion' | 'inputIcon' | 'mode' | 'getInputElement' | 'backfill'
+ | 'showTreeIcon'
+ | 'treeMotion'
+ | 'inputIcon'
+ | 'mode'
+ | 'getInputElement'
+ | 'backfill'
+ | 'treeLine'
> {
suffixIcon?: React.ReactNode;
size?: SizeType;
bordered?: boolean;
+ treeLine?: TreeProps['showLine'];
}
export interface RefTreeSelectProps {
@@ -140,6 +147,7 @@ const InternalTreeSelect = (
treeCheckable={
treeCheckable ? : treeCheckable
}
+ treeLine={!!treeLine}
inputIcon={suffixIcon}
multiple={multiple}
removeIcon={removeIcon}
diff --git a/components/tree-select/index.zh-CN.md b/components/tree-select/index.zh-CN.md
index 31c8549ed8..379965ca89 100644
--- a/components/tree-select/index.zh-CN.md
+++ b/components/tree-select/index.zh-CN.md
@@ -51,6 +51,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Ax4DA0njr/TreeSelect.svg
| treeDefaultExpandedKeys | 默认展开的树节点 | string\[] | - | |
| treeExpandedKeys | 设置展开的树节点 | string\[] | - | |
| treeIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | |
+| treeLine | 是否展示线条样式,请参考 [Tree - showLine](/components/tree/#components-tree-demo-line) | boolean \| object | false | 4.17.0 |
| treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | string | `value` | |
| treeNodeLabelProp | 作为显示的 prop 设置 | string | `title` | |
| value | 指定当前选中的条目 | string \| string\[] | - | |
@@ -63,25 +64,25 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Ax4DA0njr/TreeSelect.svg
### Tree 方法
-| 名称 | 描述 | 版本 |
-| --- | --- | --- |
-| blur() | 移除焦点 | |
-| focus() | 获取焦点 | |
+| 名称 | 描述 | 版本 |
+| ------- | -------- | ---- |
+| blur() | 移除焦点 | |
+| focus() | 获取焦点 | |
### TreeNode props
> 建议使用 treeData 来代替 TreeNode,免去手工构造麻烦
-| 参数 | 说明 | 类型 | 默认值 | 版本 |
-| --- | --- | --- | --- | --- |
-| checkable | 当树为 Checkbox 时,设置独立节点是否展示 Checkbox | boolean | - | |
-| disableCheckbox | 禁掉 Checkbox | boolean | false | |
-| disabled | 是否禁用 | boolean | false | |
-| isLeaf | 是否是叶子节点 | boolean | false | |
-| key | 此项必须设置(其值在整个树范围内唯一) | string | - | |
-| selectable | 是否可选 | boolean | true | |
-| title | 树节点显示的内容 | ReactNode | `---` | |
-| value | 默认根据此属性值进行筛选(其值在整个树范围内唯一) | string | - | |
+| 参数 | 说明 | 类型 | 默认值 | 版本 |
+| --------------- | -------------------------------------------------- | --------- | ------ | ---- |
+| checkable | 当树为 Checkbox 时,设置独立节点是否展示 Checkbox | boolean | - | |
+| disableCheckbox | 禁掉 Checkbox | boolean | false | |
+| disabled | 是否禁用 | boolean | false | |
+| isLeaf | 是否是叶子节点 | boolean | false | |
+| key | 此项必须设置(其值在整个树范围内唯一) | string | - | |
+| selectable | 是否可选 | boolean | true | |
+| title | 树节点显示的内容 | ReactNode | `---` | |
+| value | 默认根据此属性值进行筛选(其值在整个树范围内唯一) | string | - | |
## FAQ
diff --git a/components/tree-select/style/index.less b/components/tree-select/style/index.less
index e6672b5872..b2cf719f36 100644
--- a/components/tree-select/style/index.less
+++ b/components/tree-select/style/index.less
@@ -11,7 +11,7 @@
.@{tree-select-prefix-cls} {
// ======================= Dropdown =======================
&-dropdown {
- padding: @padding-xs (@padding-xs / 2) 0;
+ padding: @padding-xs (@padding-xs / 2);
&-rtl {
direction: rtl;
@@ -24,8 +24,6 @@
align-items: stretch;
.@{select-tree-prefix-cls}-treenode {
- padding-bottom: @padding-xs;
-
.@{select-tree-prefix-cls}-node-content-wrapper {
flex: auto;
}
diff --git a/components/tree/style/mixin.less b/components/tree/style/mixin.less
index 197c206625..b8030a77db 100644
--- a/components/tree/style/mixin.less
+++ b/components/tree/style/mixin.less
@@ -1,7 +1,6 @@
@import '../../style/mixins/index';
@tree-prefix-cls: ~'@{ant-prefix}-tree';
-@tree-node-prefix-cls: ~'@{tree-prefix-cls}-treenode';
@select-tree-prefix-cls: ~'@{ant-prefix}-select-tree';
@tree-motion: ~'@{ant-prefix}-motion-collapse';
@tree-node-padding: (@padding-xs / 2);
@@ -259,15 +258,15 @@
}
}
}
-}
-.@{tree-node-prefix-cls}-leaf-last {
- .@{tree-prefix-cls}-switcher {
- &-leaf-line {
- &::before {
- top: auto !important;
- bottom: auto !important;
- height: @tree-title-height - 10px !important;
+ .@{custom-tree-node-prefix-cls}-leaf-last {
+ .@{custom-tree-prefix-cls}-switcher {
+ &-leaf-line {
+ &::before {
+ top: auto !important;
+ bottom: auto !important;
+ height: @tree-title-height - 10px !important;
+ }
}
}
}
diff --git a/package.json b/package.json
index 956fa3acb4..9d5f51ee6d 100644
--- a/package.json
+++ b/package.json
@@ -122,12 +122,12 @@
"rc-dialog": "~8.5.1",
"rc-drawer": "~4.3.0",
"rc-dropdown": "~3.2.0",
- "rc-field-form": "~1.20.0",
+ "rc-field-form": "~1.21.0-2",
"rc-image": "~5.2.4",
"rc-input-number": "~7.1.0",
"rc-mentions": "~1.6.1",
"rc-menu": "~9.0.9",
- "rc-motion": "^2.4.0",
+ "rc-motion": "^2.4.4",
"rc-notification": "~4.5.7",
"rc-pagination": "~3.1.6",
"rc-picker": "~2.5.10",
@@ -138,7 +138,7 @@
"rc-slider": "~9.7.1",
"rc-steps": "~4.1.0",
"rc-switch": "~3.2.0",
- "rc-table": "~7.15.1",
+ "rc-table": "~7.16.0",
"rc-tabs": "~11.9.1",
"rc-textarea": "~0.3.0",
"rc-tooltip": "~5.1.1",
|