mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-24 02:20:01 +08:00
Merge pull request #22025 from ant-design/master-to-merge-feature
chore: 🔨 merge master into feature
This commit is contained in:
commit
64bbe4e566
@ -15,6 +15,40 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.0.2
|
||||
|
||||
`2020-03-08`
|
||||
|
||||
- Form
|
||||
- 🐞 Fix nest Form.Item dynamic remove will warning in React. [#21896](https://github.com/ant-design/ant-design/pull/21896)
|
||||
- ⚡️ Form `useForm` now return same instance for perfermance. [#21927](https://github.com/ant-design/ant-design/pull/21927)
|
||||
- ⚡️ Refactor Form.Item render logic that will only render once when children is a pure component. [#21991](https://github.com/ant-design/ant-design/pull/21991)
|
||||
- ⚡️ FormContext use a memoized value to avoid trigger FormItem's unintentional renders. [#21980](https://github.com/ant-design/ant-design/pull/21980) [@qiqiboy](https://github.com/qiqiboy)
|
||||
- Table
|
||||
- 🐞 Fix Table dropdown popup at abnormal direction. [#21905](https://github.com/ant-design/ant-design/pull/21905)
|
||||
- 🐞 Fix Table `expandIconColumnIndex` display order with `rowSelection`. [#21915](https://github.com/ant-design/ant-design/pull/21915)
|
||||
- 🐞 Fix Table `size="small"` header background color is not same as other size. [#21942](https://github.com/ant-design/ant-design/pull/21942)
|
||||
- 🐞 Fix Table `className` and `style` works on wrong node. [#21974](https://github.com/ant-design/ant-design/pull/21974)
|
||||
- Select
|
||||
- 🐞 Fix Select align issue with empty string value. [#21880](https://github.com/ant-design/ant-design/pull/21880)
|
||||
- 🐞 Fix small size Select tag text not align middle. [#21940](https://github.com/ant-design/ant-design/pull/21940) [@xrkffgg](https://github.com/xrkffgg)
|
||||
- Menu
|
||||
- 🐞 Fix Menu bottom margin is missing. [#21867](https://github.com/ant-design/ant-design/pull/21867)
|
||||
- 🐞 Fix horizontal Menu extra margin of Menu.Item with only icon. [#21925](https://github.com/ant-design/ant-design/pull/21925)
|
||||
- 🐞 Fix Menu popup menu overflow issue when contains too many items. [#21930](https://github.com/ant-design/ant-design/pull/21930)
|
||||
- 🐞 Fix Badge animation when switch between 10 and 11. [#21834](https://github.com/ant-design/ant-design/pull/21834) [@wendellhu95](https://github.com/wendellhu95)
|
||||
- 🐞 Fix Radio.Button inside Tooltip throws `Function components cannot be given refs` warning. [#21895](https://github.com/ant-design/ant-design/pull/21895) [@AshoneA](https://github.com/AshoneA)
|
||||
- 🐞 Fix Descriptions miss style when content is falsy. [#21901](https://github.com/ant-design/ant-design/pull/21901)
|
||||
- 🐞 Fix DatePicker cursor style on `seperator`. [#21937](https://github.com/ant-design/ant-design/pull/21937) [@xrkffgg](https://github.com/xrkffgg)
|
||||
- 🐞 Fix ConfigProvider `prefixCls` not working on Input.Password. [#21953](https://github.com/ant-design/ant-design/pull/21953) [@tdida](https://github.com/tdida)
|
||||
- 🐞 Fix Carousel `dots` not align center. [#21960](https://github.com/ant-design/ant-design/pull/21960) [@liusiasi](https://github.com/liusiasi)
|
||||
- 🐞 Fix Input.Search border style in `rtl` mode. [#21946](https://github.com/ant-design/ant-design/pull/21946) [@xrkffgg](https://github.com/xrkffgg)
|
||||
- Less
|
||||
- 🆕 Add `@outline-fade` variable. [#20227](https://github.com/ant-design/ant-design/pull/20227) [@Satloff](https://github.com/Satloff)
|
||||
- 🆕 Add `@form-item-label-height` variable. [#21912](https://github.com/ant-design/ant-design/pull/21912)
|
||||
- TypeScript
|
||||
- 🌟 Improve Form.Item `renderProps` definite. [#21911](https://github.com/ant-design/ant-design/pull/21911)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
`2020-03-04`
|
||||
@ -297,6 +331,7 @@ Ant Design 4.0-rc released! Here is the release [document](https://github.com/an
|
||||
- 🌟 The range selector can be set to `disabled` separately for the start and end time.
|
||||
- 🌟 The range selector allows empty start and end times.
|
||||
- 🌟 Optimized manual input and keyboard interaction support.
|
||||
- 🌟 Added `inputReadOnly` to disable manual input.
|
||||
- 🌟 Remove Icon and use `@ ant-design / icons` instead. [#18217](https://github.com/ant-design/ant-design/pull/18217)
|
||||
- Skeleton
|
||||
- 🌟 Support Skeleton.Avatar placeholder component. [#19898](https://github.com/ant-design/ant-design/pull/19898) [@Rustin-Liu](https://github.com/Rustin-Liu)
|
||||
|
@ -15,6 +15,40 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 4.0.2
|
||||
|
||||
`2020-03-08`
|
||||
|
||||
- Form
|
||||
- 🐞 修复嵌套 Form.Item 移除会导致 React 报警告的问题。[#21896](https://github.com/ant-design/ant-design/pull/21896)
|
||||
- ⚡️ `Form.useForm` 现在将返回相同的实例以优化重复渲染的问题。[#21927](https://github.com/ant-design/ant-design/pull/21927)
|
||||
- ⚡️ 重构 Form.Item 渲染逻辑以使其子元素为纯组件时值变更只会渲染一次。[#21991](https://github.com/ant-design/ant-design/pull/21991)
|
||||
- ⚡️ FormContext 使用 memoized 值避免 Form.Item 产生额外的渲染。[#21980](https://github.com/ant-design/ant-design/pull/21980) [@qiqiboy](https://github.com/qiqiboy)
|
||||
- Table
|
||||
- 🐞 修复 Table 内浮层组件弹出方向异常的问题。[#21905](https://github.com/ant-design/ant-design/pull/21905)
|
||||
- 🐞 修复 Table `className` 和 `style` 作用在了错误的元素上的问题。[#21974](https://github.com/ant-design/ant-design/pull/21974)
|
||||
- 🐞 修复 Table `expandIconColumnIndex` 与 `rowSelection` 共用时的展示顺序问题。[#21915](https://github.com/ant-design/ant-design/pull/21915)
|
||||
- 🐞 修复 Table `size="small"` 时表头颜色和其他尺寸不一致的问题。[#21942](https://github.com/ant-design/ant-design/pull/21942)
|
||||
- Select
|
||||
- 🐞 修复 Select 在空字符串值时的样式对齐问题。[#21880](https://github.com/ant-design/ant-design/pull/21880)
|
||||
- 🐞 修复小号 Select 在多选模式下 `tag` 文字不居中的问题。[#21940](https://github.com/ant-design/ant-design/pull/21940) [@xrkffgg](https://github.com/xrkffgg)
|
||||
- Menu
|
||||
- 🐞 修复 Menu 弹出菜单底部边距丢失的问题。[#21867](https://github.com/ant-design/ant-design/pull/21867)
|
||||
- 🐞 修复 Menu 水平模式下 Menu.Item 只有一个 Icon 时仍然有额外 `margin` 的问题。[#21925](https://github.com/ant-design/ant-design/pull/21925)
|
||||
- 🐞 修复 Menu 弹出菜单超出屏幕高度的问题。[#21930](https://github.com/ant-design/ant-design/pull/21930)
|
||||
- 🐞 修复 Badge 数字在 10 和 11 切换时的动画错误。[#21834](https://github.com/ant-design/ant-design/pull/21834) [@wendellhu95](https://github.com/wendellhu95)
|
||||
- 🐞 修复 Radio.Button 上使用 Tooltip 会报 `Function components cannot be given refs` 警告。[#21895](https://github.com/ant-design/ant-design/pull/21895)
|
||||
- 🐞 修复 Descriptions 内容为 falsy 值时样式丢失的问题。[#21901](https://github.com/ant-design/ant-design/pull/21901)
|
||||
- 🐞 修复 DatePicker 在分隔符上的鼠标手型。[#21937](https://github.com/ant-design/ant-design/pull/21937) [@xrkffgg](https://github.com/xrkffgg)
|
||||
- 🐞 修复 ConfigProvider `prefixCls` 在 Input.Password 上不生效的问题。[#21953](https://github.com/ant-design/ant-design/pull/21953) [@tdida](https://github.com/tdida)
|
||||
- 🐞 修复 Carousel `dots` 控件不居中的问题。[#21960](https://github.com/ant-design/ant-design/pull/21960) [@liusiasi](https://github.com/liusiasi)
|
||||
- 🐞 修复 Input.Search 边框高亮样式在 `rtl` 模式下丢失的问题。[#21946](https://github.com/ant-design/ant-design/pull/21946) [@xrkffgg](https://github.com/xrkffgg)
|
||||
- Less
|
||||
- 🆕 新增 `@outline-fade` 变量。[#20227](https://github.com/ant-design/ant-design/pull/20227) [@Satloff](https://github.com/Satloff)
|
||||
- 🆕 新增 `@form-item-label-height` 变量。[#21912](https://github.com/ant-design/ant-design/pull/21912)
|
||||
- TypeScript
|
||||
- 🌟 增强 Form.Item `renderProps` 定义。[#21911](https://github.com/ant-design/ant-design/pull/21911)
|
||||
|
||||
## 4.0.1
|
||||
|
||||
`2020-03-04`
|
||||
@ -297,6 +331,7 @@ Ant Design 4.0-rc 发布,发布文档请查看[此处](https://github.com/ant-
|
||||
- 🌟 范围选择器可以为开始与结束时间单独设置 `disabled`。
|
||||
- 🌟 范围选择器可以允许开始与结束时间为空。
|
||||
- 🌟 优化手工输入与键盘交互支持。
|
||||
- 🌟 支持 `inputReadOnly` 禁用手动输入。
|
||||
- 🌟 移除 Icon,使用 `@ant-design/icons` 代替。[#18217](https://github.com/ant-design/ant-design/pull/18217)
|
||||
- Skeleton
|
||||
- 🌟 支持 Skeleton.Avatar 占位组件。[#19898](https://github.com/ant-design/ant-design/pull/19898) [@Rustin-Liu](https://github.com/Rustin-Liu)
|
||||
|
@ -30,7 +30,7 @@ A breadcrumb displays the current location within a hierarchy. It allows going b
|
||||
| href | Target of hyperlink | string | - | |
|
||||
| overlay | The dropdown menu | [Menu](/components/menu) \| () => Menu | - | |
|
||||
| onClick | Set the handler to handle `click` event | (e:MouseEvent)=>void | - | |
|
||||
| dropdownProps | The dropdown props | [Dropdown](/components/dropdown) | - | |
|
||||
| dropdownProps | The dropdown props | [Dropdown](/components/dropdown) | - | |
|
||||
|
||||
### Breadcrumb.Separator
|
||||
|
||||
|
@ -26,12 +26,12 @@ title: Breadcrumb
|
||||
|
||||
### Breadcrumb.Item
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ------- | -------------- | -------------------------------------- | ------ | ---- |
|
||||
| href | 链接的目的地 | string | - | |
|
||||
| overlay | 下拉菜单的内容 | [Menu](/components/menu) \| () => Menu | - | |
|
||||
| onClick | 单击事件 | (e:MouseEvent)=>void | - | |
|
||||
| dropdownProps | 弹出下拉菜单的自定义配置 | [Dropdown](/components/dropdown) | - | |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| href | 链接的目的地 | string | - | |
|
||||
| overlay | 下拉菜单的内容 | [Menu](/components/menu) \| () => Menu | - | |
|
||||
| onClick | 单击事件 | (e:MouseEvent)=>void | - | |
|
||||
| dropdownProps | 弹出下拉菜单的自定义配置 | [Dropdown](/components/dropdown) | - | |
|
||||
|
||||
### Breadcrumb.Separator
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
// mixins for button
|
||||
// ------------------------
|
||||
.button-size(@height; @padding-horizontal; @font-size; @border-radius) {
|
||||
@padding-vertical: round((@height - @font-size * @line-height-base) / 2 * 10) / 10 -
|
||||
@border-width-base;
|
||||
|
||||
@padding-vertical: max(
|
||||
round((@height - @font-size * @line-height-base) / 2 * 10) / 10 - @border-width-base,
|
||||
0
|
||||
);
|
||||
height: @height;
|
||||
padding: @padding-vertical @padding-horizontal;
|
||||
font-size: @font-size;
|
||||
|
@ -20,7 +20,7 @@ A carousel component. Scales with its container.
|
||||
| autoplay | Whether to scroll automatically | boolean | `false` | |
|
||||
| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
|
||||
| dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | bottom | |
|
||||
| dots | Whether to show the dots at the bottom of the gallery, `object` for `dotsClass` and any others | boolean \| { className?:string } | `true` | |
|
||||
| dots | Whether to show the dots at the bottom of the gallery, `object` for `dotsClass` and any others | boolean \| { className?:string } | `true` | |
|
||||
| easing | Transition interpolation function name | string | `linear` | |
|
||||
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` | |
|
||||
|
||||
|
@ -181,7 +181,7 @@
|
||||
justify-content: center;
|
||||
margin-right: 15%;
|
||||
margin-left: 15%;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
|
||||
.@{carousel-prefix-cls}-rtl& {
|
||||
|
@ -7119,6 +7119,44 @@ exports[`ConfigProvider components Input configProvider 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="config-input-password config-input-affix-wrapper"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
class="config-input"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="config-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="eye-invisible"
|
||||
class="anticon anticon-eye-invisible config-input-password-icon"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="eye-invisible"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
|
||||
/>
|
||||
<path
|
||||
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<textarea
|
||||
class="config-input"
|
||||
/>
|
||||
@ -7170,6 +7208,44 @@ exports[`ConfigProvider components Input normal 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-password ant-input-affix-wrapper"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
class="ant-input"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="eye-invisible"
|
||||
class="anticon anticon-eye-invisible ant-input-password-icon"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="eye-invisible"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
|
||||
/>
|
||||
<path
|
||||
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<textarea
|
||||
class="ant-input"
|
||||
/>
|
||||
@ -7221,6 +7297,44 @@ exports[`ConfigProvider components Input prefixCls 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="prefix-Input ant-input-affix-wrapper"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
class="ant-input"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="eye-invisible"
|
||||
class="anticon anticon-eye-invisible prefix-Input-icon"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="eye-invisible"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
|
||||
/>
|
||||
<path
|
||||
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<textarea
|
||||
class="prefix-Input"
|
||||
/>
|
||||
|
@ -290,6 +290,7 @@ describe('ConfigProvider', () => {
|
||||
<Input {...props} />
|
||||
<Input.Search {...props} />
|
||||
</Input.Group>
|
||||
<Input.Password {...props} />
|
||||
<Input.TextArea {...props} />
|
||||
</div>
|
||||
));
|
||||
|
@ -65,6 +65,7 @@ The following APIs are shared by DatePicker, YearPicker, MonthPicker, RangePicke
|
||||
| style | to customize the style of the input box | object | {} | |
|
||||
| onOpenChange | a callback function, can be executed whether the popup calendar is popped up or closed | function(status) | - | |
|
||||
| onPanelChange | callback when picker panel mode is changed | function(value, mode) | - | |
|
||||
| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false | |
|
||||
|
||||
### Common Methods
|
||||
|
||||
|
@ -67,6 +67,7 @@ import 'moment/locale/zh-cn';
|
||||
| style | 自定义输入框样式 | object | {} | |
|
||||
| onOpenChange | 弹出日历和关闭日历的回调 | function(status) | 无 | |
|
||||
| onPanelChange | 日历面板切换的回调 | function(value, mode) | - | |
|
||||
| inputReadOnly | 设置输入框为只读(避免在移动设备上打开虚拟键盘) | boolean | false | |
|
||||
|
||||
### 共同的方法
|
||||
|
||||
|
@ -496,6 +496,7 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
|
||||
</h3>
|
||||
<div
|
||||
class="ant-table-wrapper"
|
||||
style="margin-top:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-spin-nested-loading"
|
||||
@ -505,7 +506,6 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-table"
|
||||
style="margin-top:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-table-container"
|
||||
|
@ -74,6 +74,18 @@ const InternalForm: React.ForwardRefRenderFunction<unknown, FormProps> = (props,
|
||||
const [wrapForm] = useForm(form);
|
||||
wrapForm.__INTERNAL__.name = name;
|
||||
|
||||
const formContextValue = React.useMemo(
|
||||
() => ({
|
||||
name,
|
||||
labelAlign,
|
||||
labelCol,
|
||||
wrapperCol,
|
||||
vertical: layout === 'vertical',
|
||||
colon,
|
||||
}),
|
||||
[name, labelAlign, labelCol, wrapperCol, layout, colon],
|
||||
);
|
||||
|
||||
React.useImperativeHandle(ref, () => wrapForm);
|
||||
|
||||
const onInternalFinishFailed = (errorInfo: ValidateErrorEntity) => {
|
||||
@ -89,14 +101,7 @@ const InternalForm: React.ForwardRefRenderFunction<unknown, FormProps> = (props,
|
||||
return (
|
||||
<SizeContextProvider size={size}>
|
||||
<FormContext.Provider
|
||||
value={{
|
||||
name,
|
||||
labelAlign,
|
||||
labelCol,
|
||||
wrapperCol,
|
||||
vertical: layout === 'vertical',
|
||||
colon,
|
||||
}}
|
||||
value={formContextValue}
|
||||
>
|
||||
<FieldForm
|
||||
id={name}
|
||||
|
@ -21,6 +21,21 @@ type RenderChildren = (form: FormInstance) => React.ReactNode;
|
||||
type RcFieldProps = Omit<FieldProps, 'children'>;
|
||||
type ChildrenType = React.ReactElement | RenderChildren | React.ReactElement[] | null;
|
||||
|
||||
interface MemoInputProps {
|
||||
value: any;
|
||||
update: number;
|
||||
children: any;
|
||||
}
|
||||
|
||||
const MemoInput = React.memo<MemoInputProps>(
|
||||
({ children }) => {
|
||||
return children;
|
||||
},
|
||||
(prev, next) => {
|
||||
return prev.value === next.value && prev.update === next.update;
|
||||
},
|
||||
);
|
||||
|
||||
export interface FormItemProps
|
||||
extends FormItemLabelProps,
|
||||
FormItemInputProps,
|
||||
@ -217,6 +232,10 @@ function FormItem(props: FormItemProps): React.ReactElement {
|
||||
return renderLayout(children);
|
||||
}
|
||||
|
||||
// Record for real component render
|
||||
const updateRef = React.useRef(0);
|
||||
updateRef.current += 1;
|
||||
|
||||
const variables: Record<string, string> = {};
|
||||
if (typeof label === 'string') {
|
||||
variables.label = label;
|
||||
@ -294,10 +313,7 @@ function FormItem(props: FormItemProps): React.ReactElement {
|
||||
const childProps = { ...children.props, ...mergedControl };
|
||||
|
||||
// We should keep user origin event handler
|
||||
const triggers = new Set<string>();
|
||||
[...toArray(trigger), ...toArray(validateTrigger)].forEach(eventName => {
|
||||
triggers.add(eventName);
|
||||
});
|
||||
const triggers = new Set<string>([...toArray(trigger), ...toArray(validateTrigger)]);
|
||||
|
||||
triggers.forEach(eventName => {
|
||||
childProps[eventName] = (...args: any[]) => {
|
||||
@ -306,7 +322,14 @@ function FormItem(props: FormItemProps): React.ReactElement {
|
||||
};
|
||||
});
|
||||
|
||||
childNode = React.cloneElement(children, childProps);
|
||||
childNode = (
|
||||
<MemoInput
|
||||
value={mergedControl[props.valuePropName || 'value']}
|
||||
update={updateRef.current}
|
||||
>
|
||||
{React.cloneElement(children, childProps)}
|
||||
</MemoInput>
|
||||
);
|
||||
} else if (isRenderProps && shouldUpdate && !hasName) {
|
||||
childNode = (children as RenderChildren)(context);
|
||||
} else {
|
||||
|
@ -643,4 +643,35 @@ describe('Form', () => {
|
||||
}
|
||||
expect(instances.size).toEqual(1);
|
||||
});
|
||||
|
||||
it('avoid re-render', async () => {
|
||||
let renderTimes = 0;
|
||||
|
||||
const MyInput = ({ value = '', ...props }) => {
|
||||
renderTimes += 1;
|
||||
return <input value={value} {...props} />;
|
||||
};
|
||||
|
||||
const Demo = () => (
|
||||
<Form>
|
||||
<Form.Item name="username" rules={[{ required: true }]}>
|
||||
<MyInput />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
renderTimes = 0;
|
||||
|
||||
wrapper.find('input').simulate('change', {
|
||||
target: {
|
||||
value: 'a',
|
||||
},
|
||||
});
|
||||
|
||||
await delay();
|
||||
|
||||
expect(renderTimes).toEqual(1);
|
||||
expect(wrapper.find('input').props().value).toEqual('a');
|
||||
});
|
||||
});
|
||||
|
@ -20,6 +20,7 @@ ReactDOM.render(<IconDisplay />, mountNode);
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| className | className of Icon | `string` | - | |
|
||||
| style | Style properties of icon, like `fontSize` and `color` | CSSProperties | - | |
|
||||
| spin | Rotate icon with animation | boolean | false | |
|
||||
| rotate | Rotate by n degrees (not working in IE9) | number | - | |
|
||||
|
@ -27,6 +27,7 @@ ReactDOM.render(<IconDisplay />, mountNode);
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| className | 设置图标的样式名 | `string` | - | |
|
||||
| style | 设置图标的样式,例如 `fontSize` 和 `color` | CSSProperties | - | |
|
||||
| spin | 是否有旋转动画 | boolean | false | |
|
||||
| rotate | 图标旋转角度(IE9 无效) | number | - | |
|
||||
|
@ -4,6 +4,7 @@ import omit from 'omit.js';
|
||||
import EyeOutlined from '@ant-design/icons/EyeOutlined';
|
||||
import EyeInvisibleOutlined from '@ant-design/icons/EyeInvisibleOutlined';
|
||||
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import Input, { InputProps } from './Input';
|
||||
|
||||
export interface PasswordProps extends InputProps {
|
||||
@ -25,8 +26,6 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
|
||||
input: HTMLInputElement;
|
||||
|
||||
static defaultProps = {
|
||||
inputPrefixCls: 'ant-input',
|
||||
prefixCls: 'ant-input-password',
|
||||
action: 'click',
|
||||
visibilityToggle: true,
|
||||
};
|
||||
@ -44,8 +43,8 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
|
||||
this.setState(({ visible }) => ({ visible: !visible }));
|
||||
};
|
||||
|
||||
getIcon() {
|
||||
const { prefixCls, action } = this.props;
|
||||
getIcon = (prefixCls: string) => {
|
||||
const { action } = this.props;
|
||||
const iconTrigger = ActionMap[action!] || '';
|
||||
const icon = this.state.visible ? EyeOutlined : EyeInvisibleOutlined;
|
||||
const iconProps = {
|
||||
@ -59,7 +58,7 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
|
||||
},
|
||||
};
|
||||
return React.createElement(icon, iconProps);
|
||||
}
|
||||
};
|
||||
|
||||
saveInput = (instance: Input) => {
|
||||
if (instance && instance.input) {
|
||||
@ -79,19 +78,24 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
|
||||
this.input.select();
|
||||
}
|
||||
|
||||
render() {
|
||||
renderPassword = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const {
|
||||
className,
|
||||
prefixCls,
|
||||
inputPrefixCls,
|
||||
prefixCls: customizePrefixCls,
|
||||
inputPrefixCls: customizeInputPrefixCls,
|
||||
size,
|
||||
visibilityToggle,
|
||||
...restProps
|
||||
} = this.props;
|
||||
const suffixIcon = visibilityToggle && this.getIcon();
|
||||
|
||||
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
|
||||
const prefixCls = getPrefixCls('input-password', customizePrefixCls);
|
||||
|
||||
const suffixIcon = visibilityToggle && this.getIcon(prefixCls);
|
||||
const inputClassName = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-${size}`]: !!size,
|
||||
});
|
||||
|
||||
const props = {
|
||||
...omit(restProps, ['suffix']),
|
||||
type: this.state.visible ? 'text' : 'password',
|
||||
@ -100,9 +104,15 @@ export default class Password extends React.Component<PasswordProps, PasswordSta
|
||||
suffix: suffixIcon,
|
||||
ref: this.saveInput,
|
||||
};
|
||||
|
||||
if (size) {
|
||||
props.size = size;
|
||||
}
|
||||
|
||||
return <Input {...props} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderPassword}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ class ResizableTextArea extends React.Component<TextAreaProps, TextAreaState> {
|
||||
this.setState({ resizeStatus: RESIZE_STATUS_RESIZED }, () => {
|
||||
this.resizeFrameId = raf(() => {
|
||||
this.setState({ resizeStatus: RESIZE_STATUS_NONE });
|
||||
this.fixFirefoxAutoScroll();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -99,6 +100,21 @@ class ResizableTextArea extends React.Component<TextAreaProps, TextAreaState> {
|
||||
raf.cancel(this.resizeFrameId);
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/21870
|
||||
fixFirefoxAutoScroll() {
|
||||
try {
|
||||
if (document.activeElement === this.textArea) {
|
||||
const currentStart = this.textArea.selectionStart;
|
||||
const currentEnd = this.textArea.selectionEnd;
|
||||
this.textArea.setSelectionRange(currentStart, currentEnd);
|
||||
}
|
||||
} catch (e) {
|
||||
// Fix error in Chrome:
|
||||
// Failed to read the 'selectionStart' property from 'HTMLInputElement'
|
||||
// http://stackoverflow.com/q/21177489/3040605
|
||||
}
|
||||
}
|
||||
|
||||
renderTextArea = () => {
|
||||
const { prefixCls, autoSize, onResize, className, disabled } = this.props;
|
||||
const { textareaStyles, resizeStatus } = this.state;
|
||||
|
@ -570,64 +570,6 @@ exports[`renders ./components/input/demo/align.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow"
|
||||
style="width:100px"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-item"
|
||||
>
|
||||
jack
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
|
||||
style="width:100px"
|
||||
@ -1534,6 +1476,7 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-select-single ant-select-show-arrow"
|
||||
style="width:30%"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
@ -1591,7 +1534,7 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-select ant-select-auto-complete ant-select-single ant-select-show-search"
|
||||
style="width:200px"
|
||||
style="width:70%"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
|
@ -145,8 +145,8 @@ describe('TextArea', () => {
|
||||
|
||||
it('should trigger onResize', () => {
|
||||
const onResize = jest.fn();
|
||||
const wrapper = mount(<TextArea onResize={onResize} autosize />);
|
||||
|
||||
const wrapper = mount(<TextArea onResize={onResize} autoSize />);
|
||||
jest.runAllTimers();
|
||||
wrapper
|
||||
.find('ResizeObserver')
|
||||
.instance()
|
||||
@ -284,4 +284,23 @@ describe('TextArea allowClear', () => {
|
||||
wrapper.find('.test-suffix').simulate('mouseUp');
|
||||
expect(onFocus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('scroll to bottom when autoSize', () => {
|
||||
jest.useFakeTimers();
|
||||
const wrapper = mount(<Input.TextArea autoSize />, { attachTo: document.body });
|
||||
wrapper.find('textarea').simulate('focus');
|
||||
wrapper
|
||||
.find('textarea')
|
||||
.getDOMNode()
|
||||
.focus();
|
||||
const setSelectionRangeFn = jest.spyOn(
|
||||
wrapper.find('textarea').getDOMNode(),
|
||||
'setSelectionRange',
|
||||
);
|
||||
wrapper.find('textarea').simulate('input', { target: { value: '\n1' } });
|
||||
jest.runAllTimers();
|
||||
jest.useRealTimers();
|
||||
expect(setSelectionRangeFn).toHaveBeenCalled();
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
@ -83,7 +83,6 @@ ReactDOM.render(
|
||||
</Option>
|
||||
<Option value="Yiminghe">yiminghe</Option>
|
||||
</Select>
|
||||
<Select style={{ width: 100 }} combobox defaultValue="jack" />
|
||||
<TreeSelect style={{ width: 100 }} />
|
||||
<Cascader defaultValue={['zhejiang', 'hangzhou', 'xihu']} options={options} />
|
||||
<RangePicker />
|
||||
@ -93,9 +92,7 @@ ReactDOM.render(
|
||||
<RadioButton value="b">Shanghai</RadioButton>
|
||||
</RadioGroup>
|
||||
<AutoComplete style={{ width: 100 }} placeholder="input here" />
|
||||
|
||||
<br />
|
||||
|
||||
<Input prefix="$" addonBefore="Http://" addonAfter=".com" defaultValue="mysite" />
|
||||
</div>,
|
||||
mountNode,
|
||||
|
@ -20,7 +20,6 @@ Note: You don't need `Col` to control the width in the `compact` mode.
|
||||
```jsx
|
||||
import { Input, Col, Row, Select, InputNumber, DatePicker, AutoComplete, Cascader } from 'antd';
|
||||
|
||||
const InputGroup = Input.Group;
|
||||
const { Option } = Select;
|
||||
|
||||
const options = [
|
||||
@ -58,125 +57,107 @@ const options = [
|
||||
},
|
||||
];
|
||||
|
||||
class CompactDemo extends React.Component {
|
||||
state = {
|
||||
dataSource: [],
|
||||
};
|
||||
const App = () => (
|
||||
<div className="site-input-group-wrapper">
|
||||
<Input.Group size="large">
|
||||
<Row gutter={8}>
|
||||
<Col span={5}>
|
||||
<Input defaultValue="0571" />
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Input defaultValue="26888888" />
|
||||
</Col>
|
||||
</Row>
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Input style={{ width: '20%' }} defaultValue="0571" />
|
||||
<Input style={{ width: '30%' }} defaultValue="26888888" />
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Select defaultValue="Zhejiang">
|
||||
<Option value="Zhejiang">Zhejiang</Option>
|
||||
<Option value="Jiangsu">Jiangsu</Option>
|
||||
</Select>
|
||||
<Input style={{ width: '50%' }} defaultValue="Xihu District, Hangzhou" />
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Select defaultValue="Option1">
|
||||
<Option value="Option1">Option1</Option>
|
||||
<Option value="Option2">Option2</Option>
|
||||
</Select>
|
||||
<Input style={{ width: '50%' }} defaultValue="input content" />
|
||||
<InputNumber />
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Input style={{ width: '50%' }} defaultValue="input content" />
|
||||
<DatePicker style={{ width: '50%' }} />
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Select defaultValue="Option1-1">
|
||||
<Option value="Option1-1">Option1-1</Option>
|
||||
<Option value="Option1-2">Option1-2</Option>
|
||||
</Select>
|
||||
<Select defaultValue="Option2-2">
|
||||
<Option value="Option2-1">Option2-1</Option>
|
||||
<Option value="Option2-2">Option2-2</Option>
|
||||
</Select>
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Select defaultValue="1">
|
||||
<Option value="1">Between</Option>
|
||||
<Option value="2">Except</Option>
|
||||
</Select>
|
||||
<Input style={{ width: 100, textAlign: 'center' }} placeholder="Minimum" />
|
||||
<Input
|
||||
className="site-input-split"
|
||||
style={{
|
||||
width: 30,
|
||||
borderLeft: 0,
|
||||
borderRight: 0,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
placeholder="~"
|
||||
disabled
|
||||
/>
|
||||
<Input
|
||||
className="site-input-right"
|
||||
style={{
|
||||
width: 100,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
placeholder="Maximum"
|
||||
/>
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Select defaultValue="Sign Up" style={{ width: '30%' }}>
|
||||
<Option value="Sign Up">Sign Up</Option>
|
||||
<Option value="Sign In">Sign In</Option>
|
||||
</Select>
|
||||
<AutoComplete
|
||||
style={{ width: '70%' }}
|
||||
placeholder="Email"
|
||||
options={[{ value: 'text 1' }, { value: 'text 2' }]}
|
||||
/>
|
||||
</Input.Group>
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Select style={{ width: '30%' }} defaultValue="Home">
|
||||
<Option value="Home">Home</Option>
|
||||
<Option value="Company">Company</Option>
|
||||
</Select>
|
||||
<Cascader style={{ width: '70%' }} options={options} placeholder="Select Address" />
|
||||
</Input.Group>
|
||||
</div>
|
||||
);
|
||||
|
||||
handleChange = value => {
|
||||
this.setState({
|
||||
dataSource:
|
||||
!value || value.indexOf('@') >= 0
|
||||
? []
|
||||
: [`${value}@gmail.com`, `${value}@163.com`, `${value}@qq.com`],
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="site-input-group-wrapper">
|
||||
<InputGroup size="large">
|
||||
<Row gutter={8}>
|
||||
<Col span={5}>
|
||||
<Input defaultValue="0571" />
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Input defaultValue="26888888" />
|
||||
</Col>
|
||||
</Row>
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Input style={{ width: '20%' }} defaultValue="0571" />
|
||||
<Input style={{ width: '30%' }} defaultValue="26888888" />
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select defaultValue="Zhejiang">
|
||||
<Option value="Zhejiang">Zhejiang</Option>
|
||||
<Option value="Jiangsu">Jiangsu</Option>
|
||||
</Select>
|
||||
<Input style={{ width: '50%' }} defaultValue="Xihu District, Hangzhou" />
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select defaultValue="Option1">
|
||||
<Option value="Option1">Option1</Option>
|
||||
<Option value="Option2">Option2</Option>
|
||||
</Select>
|
||||
<Input style={{ width: '50%' }} defaultValue="input content" />
|
||||
<InputNumber />
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Input style={{ width: '50%' }} defaultValue="input content" />
|
||||
<DatePicker style={{ width: '50%' }} />
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select defaultValue="Option1-1">
|
||||
<Option value="Option1-1">Option1-1</Option>
|
||||
<Option value="Option1-2">Option1-2</Option>
|
||||
</Select>
|
||||
<Select defaultValue="Option2-2">
|
||||
<Option value="Option2-1">Option2-1</Option>
|
||||
<Option value="Option2-2">Option2-2</Option>
|
||||
</Select>
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select defaultValue="1">
|
||||
<Option value="1">Between</Option>
|
||||
<Option value="2">Except</Option>
|
||||
</Select>
|
||||
<Input style={{ width: 100, textAlign: 'center' }} placeholder="Minimum" />
|
||||
<Input
|
||||
className="site-input-split"
|
||||
style={{
|
||||
width: 30,
|
||||
borderLeft: 0,
|
||||
borderRight: 0,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
placeholder="~"
|
||||
disabled
|
||||
/>
|
||||
<Input
|
||||
className="site-input-right"
|
||||
style={{
|
||||
width: 100,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
placeholder="Maximum"
|
||||
/>
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select defaultValue="Sign Up">
|
||||
<Option value="Sign Up">Sign Up</Option>
|
||||
<Option value="Sign In">Sign In</Option>
|
||||
</Select>
|
||||
<AutoComplete
|
||||
dataSource={this.state.dataSource}
|
||||
style={{ width: 200 }}
|
||||
onChange={this.handleChange}
|
||||
placeholder="Email"
|
||||
/>
|
||||
</InputGroup>
|
||||
<br />
|
||||
<InputGroup compact>
|
||||
<Select style={{ width: '30%' }} defaultValue="Home">
|
||||
<Option value="Home">Home</Option>
|
||||
<Option value="Company">Company</Option>
|
||||
</Select>
|
||||
<Cascader style={{ width: '70%' }} options={options} placeholder="Select Address" />
|
||||
</InputGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<CompactDemo />, mountNode);
|
||||
ReactDOM.render(<App />, mountNode);
|
||||
```
|
||||
|
||||
```css
|
||||
|
@ -207,7 +207,7 @@
|
||||
}
|
||||
|
||||
&.@{menu-prefix-cls}-item-only-child {
|
||||
.@{iconfont-css-prefix} {
|
||||
> .@{iconfont-css-prefix} {
|
||||
margin-right: 0;
|
||||
|
||||
.@{menu-prefix-cls}-rtl & {
|
||||
|
@ -4,8 +4,11 @@
|
||||
@select-multiple-item-height: @input-height-base - @input-padding-vertical-base * 2; // Normal 24px
|
||||
|
||||
@select-multiple-item-spacing-half: ceil(@input-padding-vertical-base / 2);
|
||||
@select-multiple-padding: @input-padding-vertical-base - @select-multiple-item-border-width -
|
||||
@select-multiple-item-spacing-half;
|
||||
@select-multiple-padding: max(
|
||||
@input-padding-vertical-base - @select-multiple-item-border-width -
|
||||
@select-multiple-item-spacing-half,
|
||||
0
|
||||
);
|
||||
|
||||
/**
|
||||
* Do not merge `height` & `line-height` under style with `selection` & `search`,
|
||||
|
@ -344,9 +344,11 @@
|
||||
@input-padding-horizontal-base: @input-padding-horizontal;
|
||||
@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px;
|
||||
@input-padding-horizontal-lg: @input-padding-horizontal;
|
||||
@input-padding-vertical-base: round(
|
||||
(@input-height-base - @font-size-base * @line-height-base) / 2 * 10
|
||||
) / 10 - @border-width-base;
|
||||
@input-padding-vertical-base: max(
|
||||
round((@input-height-base - @font-size-base * @line-height-base) / 2 * 10) / 10 -
|
||||
@border-width-base,
|
||||
3px
|
||||
);
|
||||
@input-padding-vertical-sm: round((@input-height-sm - @font-size-base * @line-height-base) / 2 * 10) /
|
||||
10 - @border-width-base;
|
||||
@input-padding-vertical-lg: ceil((@input-height-lg - @font-size-lg * @line-height-base) / 2 * 10) /
|
||||
|
@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import RcTable from 'rc-table';
|
||||
import { TableProps as RcTableProps, INTERNAL_HOOKS } from 'rc-table/lib/Table';
|
||||
import Spin, { SpinProps } from '../spin';
|
||||
@ -85,6 +86,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
style,
|
||||
size: customizeSize,
|
||||
bordered,
|
||||
dropdownPrefixCls,
|
||||
@ -109,6 +111,9 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
locale,
|
||||
showSorterTooltip = true,
|
||||
} = props;
|
||||
|
||||
const tableProps = omit(props, ['className', 'style']) as TableProps<RecordType>;
|
||||
|
||||
const size = React.useContext(SizeContext);
|
||||
const { locale: contextLocale = defaultLocale, renderEmpty, direction } = React.useContext(
|
||||
ConfigContext,
|
||||
@ -404,12 +409,13 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
spinProps = loading;
|
||||
}
|
||||
|
||||
const wrapperClassNames = classNames(`${prefixCls}-wrapper`, {
|
||||
const wrapperClassNames = classNames(`${prefixCls}-wrapper`, className, {
|
||||
[`${prefixCls}-wrapper-rtl`]: direction === 'rtl',
|
||||
});
|
||||
return (
|
||||
<div
|
||||
className={wrapperClassNames}
|
||||
style={style}
|
||||
onTouchMove={e => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
@ -417,10 +423,10 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
|
||||
<Spin spinning={false} {...spinProps}>
|
||||
{topPaginationNode}
|
||||
<RcTable<RecordType>
|
||||
{...props}
|
||||
{...tableProps}
|
||||
expandable={mergedExpandable}
|
||||
prefixCls={prefixCls}
|
||||
className={classNames(className, {
|
||||
className={classNames({
|
||||
[`${prefixCls}-middle`]: mergedSize === 'middle',
|
||||
[`${prefixCls}-small`]: mergedSize === 'small',
|
||||
[`${prefixCls}-bordered`]: bordered,
|
||||
|
@ -9544,7 +9544,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md correctly 1`] = `
|
||||
|
||||
exports[`renders ./components/table/demo/nested-table.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-table-wrapper"
|
||||
class="ant-table-wrapper components-table-demo-nested"
|
||||
>
|
||||
<div
|
||||
class="ant-spin-nested-loading"
|
||||
@ -9553,7 +9553,7 @@ exports[`renders ./components/table/demo/nested-table.md correctly 1`] = `
|
||||
class="ant-spin-container"
|
||||
>
|
||||
<div
|
||||
class="ant-table components-table-demo-nested"
|
||||
class="ant-table"
|
||||
>
|
||||
<div
|
||||
class="ant-table-container"
|
||||
@ -13178,7 +13178,7 @@ exports[`renders ./components/table/demo/summary.md correctly 1`] = `
|
||||
|
||||
exports[`renders ./components/table/demo/virtual-list.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-table-wrapper"
|
||||
class="ant-table-wrapper virtual-table"
|
||||
>
|
||||
<div
|
||||
class="ant-spin-nested-loading"
|
||||
@ -13187,7 +13187,7 @@ exports[`renders ./components/table/demo/virtual-list.md correctly 1`] = `
|
||||
class="ant-spin-container"
|
||||
>
|
||||
<div
|
||||
class="ant-table virtual-table ant-table-fixed-header ant-table-fixed-column"
|
||||
class="ant-table ant-table-fixed-header ant-table-fixed-column"
|
||||
>
|
||||
<div
|
||||
class="ant-table-container"
|
||||
|
@ -19,27 +19,54 @@ import { Tree } from 'antd';
|
||||
|
||||
const { TreeNode } = Tree;
|
||||
|
||||
const initTreeDate = [
|
||||
interface DataNode {
|
||||
title: string;
|
||||
key: string;
|
||||
isLeaf?: boolean;
|
||||
children?: DataNode[];
|
||||
}
|
||||
|
||||
const initTreeDate: DataNode[] = [
|
||||
{ title: 'Expand to load', key: '0' },
|
||||
{ title: 'Expand to load', key: '1' },
|
||||
{ title: 'Tree Node', key: '2', isLeaf: true },
|
||||
];
|
||||
|
||||
// It's just a simple demo. You can use tree map to optimize update perf.
|
||||
function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] {
|
||||
return list.map(node => {
|
||||
if (node.key === key) {
|
||||
return {
|
||||
...node,
|
||||
children,
|
||||
};
|
||||
} else if (node.children) {
|
||||
return {
|
||||
...node,
|
||||
children: updateTreeData(node.children, key, children),
|
||||
};
|
||||
}
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
const Demo: React.FC<{}> = () => {
|
||||
const [treeData, setTreeData] = useState(initTreeDate);
|
||||
|
||||
function onLoadData({ props: { data } }) {
|
||||
function onLoadData({ key, children }) {
|
||||
return new Promise(resolve => {
|
||||
if (data.children) {
|
||||
if (children) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
data.children = [
|
||||
{ title: 'Child Node', key: `${data.key}-0` },
|
||||
{ title: 'Child Node', key: `${data.key}-1` },
|
||||
];
|
||||
setTreeData([...treeData]);
|
||||
setTreeData(origin =>
|
||||
updateTreeData(origin, key, [
|
||||
{ title: 'Child Node', key: `${key}-0` },
|
||||
{ title: 'Child Node', key: `${key}-1` },
|
||||
]),
|
||||
);
|
||||
|
||||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
@ -61,14 +88,14 @@ class Demo1 extends React.Component {
|
||||
const { treeData } = this.state;
|
||||
return new Promise(resolve => {
|
||||
const { props } = treeNode;
|
||||
if (treeNode.props.children) {
|
||||
if (treeNode.children) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
treeNode.props.dataRef.children = [
|
||||
{ title: 'Child Node', key: `${treeNode.props.eventKey}-0` },
|
||||
{ title: 'Child Node', key: `${treeNode.props.eventKey}-1` },
|
||||
treeNode.children = [
|
||||
{ title: 'Child Node', key: `${treeNode.eventKey}-0` },
|
||||
{ title: 'Child Node', key: `${treeNode.eventKey}-1` },
|
||||
];
|
||||
this.setState({
|
||||
treeData: [...this.state.treeData],
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "antd",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.2",
|
||||
"description": "An enterprise-class UI design language and React components implementation",
|
||||
"keywords": [
|
||||
"ant",
|
||||
@ -25,6 +25,10 @@
|
||||
"contributors": [
|
||||
"ant"
|
||||
],
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ant-design"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"lib",
|
||||
@ -224,7 +228,7 @@
|
||||
"react-helmet-async": "^1.0.4",
|
||||
"react-highlight-words": "^0.16.0",
|
||||
"react-infinite-scroller": "^1.2.4",
|
||||
"react-intl": "^3.1.1",
|
||||
"react-intl": "^4.1.1",
|
||||
"react-resizable": "^1.8.0",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-sticky": "^6.0.3",
|
||||
|
Loading…
Reference in New Issue
Block a user