diff --git a/.github/workflows/issue-open-check.yml b/.github/workflows/issue-open-check.yml index a7bdfaf7ab..47d2746520 100644 --- a/.github/workflows/issue-open-check.yml +++ b/.github/workflows/issue-open-check.yml @@ -8,8 +8,13 @@ jobs: check-issue: runs-on: ubuntu-latest steps: + - uses: actions-cool/check-user-permission@v1.0.0 + id: checkUser + with: + require: 'write' + - name: check invalid - if: contains(github.event.issue.body, 'ant-design-issue-helper') == false + if: (contains(github.event.issue.body, 'ant-design-issue-helper') == false) && (steps.checkUser.outputs.result == 'false') uses: actions-cool/issues-helper@v1.2 with: actions: 'create-comment,add-labels,close-issue' diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index b33b8afab9..250db3497e 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -15,7 +15,22 @@ timeline: true --- -## 4.13.0 +## 4.13.1 + +`2021-03-06` + +- 🐞 Fix `message.config` with `prefixCls` missing animation style. [#29574](https://github.com/ant-design/ant-design/pull/29574) +- 🐞 Fix Tooltip is not interactive when `visible` is `true` under some situation. [#29555](https://github.com/ant-design/ant-design/pull/29555) +- 🐞 Fix ConfigProvider within multiple page switch will lose locale issue. [#29570](https://github.com/ant-design/ant-design/pull/29570) +- 🐞 Fix Modal with hooks cannot call `update` or `destroy` before render. [#29584](https://github.com/ant-design/ant-design/pull/29584) +- 🐞 Fix Grid throw error when client support flexGap but ssr not support. [#29586](https://github.com/ant-design/ant-design/pull/29586) +- 🐞 Fix Select caret position when `mode="tags"` and `size="small"`. [#29561](https://github.com/ant-design/ant-design/pull/29561) +- 🐞 Fix Carousel `dotPosition` makes `pauseOnHover` not working. [#29587](https://github.com/ant-design/ant-design/pull/29587) [@zgoby](https://github.com/zgoby) +- 🐞 Fix Steps `responsive` prop warning. [#29599](https://github.com/ant-design/ant-design/pull/29599) +- 🐞 Fix Upload `onChange` param of `file.originFileObj` return nest Proxy object. [#29614](https://github.com/ant-design/ant-design/pull/29614) +- 🐞 Fix Descriptions under Table will not have 100% width. [#29630](https://github.com/ant-design/ant-design/pull/29630) +- TypeScript + - 🤖 Fix Drawer type declaration of `contentWrapperStyle`. [#29571](https://github.com/ant-design/ant-design/pull/29571) `2021-02-28` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index ef60cdade5..892535e0bd 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -15,6 +15,23 @@ timeline: true --- +## 4.13.1 + +`2021-03-06` + +- 🐞 修复 `message.config` 配置 `prefixCls` 时丢失淡入淡出动画的问题。[#29574](https://github.com/ant-design/ant-design/pull/29574) +- 🐞 修复 Tooltip 在某些情况下设置 `visible` 为 `true` 却无法交互的问题。[#29555](https://github.com/ant-design/ant-design/pull/29555) +- 🐞 修复多页面使用 ConfigProvider 切换时 `locale` 会丢失的问题。[#29570](https://github.com/ant-design/ant-design/pull/29570) +- 🐞 修复 Modal 的 hooks 在渲染前调用 `update` 与 `destroy` 无效的问题。[#29584](https://github.com/ant-design/ant-design/pull/29584) +- 🐞 修复 Grid ssr 时报错 `Prop style did not match`。[#29586](https://github.com/ant-design/ant-design/pull/29586) +- 🐞 修复小号 Select `tags` 模式的光标错位问题。[#29561](https://github.com/ant-design/ant-design/pull/29561) +- 🐞 修复 Carousel `dotPosition` 导致 `pauseOnHover` 失效的问题。[#29587](https://github.com/ant-design/ant-design/pull/29587) [@zgoby](https://github.com/zgoby) +- 🐞 修复 Steps 使用 `responsive` 时控制台抛出警告的问题。[#29599](https://github.com/ant-design/ant-design/pull/29599) +- 🐞 修复 Upload `onChange` 参数 `file.originFileObj` 返回嵌套 Proxy 对象的问题。[#29614](https://github.com/ant-design/ant-design/pull/29614) +- 🐞 修复 Descriptions 在 Table 下没有 100% 宽度的问题。[#29630](https://github.com/ant-design/ant-design/pull/29630) +- TypeScript + - 🤖 修复 Drawer `contentWrapperStyle` 属性类型声明。[#29571](https://github.com/ant-design/ant-design/pull/29571) + ## 4.13.0 `2021-02-28` diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index f32743b84c..2f87a802aa 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -85,7 +85,7 @@ Form field component for data bidirectional binding, validation, layout, and so | label | Label text | ReactNode | - | | | labelAlign | The text align of label | `left` \| `right` | `right` | | | labelCol | The layout of label. You can set `span` `offset` to something like `{span: 3, offset: 12}` or `sm: {span: 3, offset: 12}` same as with ``. You can set `labelCol` on Form which will not affect nest Item. If both exists, use Item first | [object](/components/grid/#Col) | - | | -| messageVariables | default validate filed info | Record<string, string> | - | 4.7.0 | +| messageVariables | The default validate field info | Record<string, string> | - | 4.7.0 | | name | Field name, support array | [NamePath](#NamePath) | - | | | normalize | Normalize value from component value before passing to Form instance. Do not support async | (value, prevValue, prevValues) => any | - | | | noStyle | No style for `true`, used as a pure field control | boolean | false | | @@ -111,13 +111,13 @@ After wrapped by `Form.Item` with `name` property, `value`(or other property def Used when there are dependencies between fields. If a field has the `dependencies` prop, this field will automatically trigger updates and validations when upstream is updated. A common scenario is a user registration form with "password" and "confirm password" fields. The "Confirm Password" validation depends on the "Password" field. After setting `dependencies`, the "Password" field update will re-trigger the validation of "Check Password". You can refer [examples](#components-form-demo-register). -`dependencies` shouldn't be used together with `shouldUpdate`. Since it may cause chaos in updating logic. +`dependencies` shouldn't be used together with `shouldUpdate`, since it may result in conflicting update logic. `dependencies` supports `Form.Item` with render props children since `4.5.0`. ### shouldUpdate -Form updates only the modified field-related components for performance optimization purposes by incremental update. In most cases, you only need to write code or do validation with the [`dependencies`](#dependencies) property. In some specific cases, such as when a new field option appears with a filed value changed, or you just want to keep some area updating by form update, you can modify the update logic of Form.Item via the `shouldUpdate`. +Form updates only the modified field-related components for performance optimization purposes by incremental update. In most cases, you only need to write code or do validation with the [`dependencies`](#dependencies) property. In some specific cases, such as when a new field option appears with a field value changed, or you just want to keep some area updating by form update, you can modify the update logic of Form.Item via the `shouldUpdate`. When `shouldUpdate` is `true`, any Form update will cause the Form.Item to be re-rendered. This is very helpful for custom rendering some areas: @@ -187,7 +187,7 @@ Provides array management for fields. ``` -Note: You should not config Form.Item `initialValue` under Form.List. It always should be configured by Form.List `initialValue` or Form `initialValues`. +Note: You should not configure Form.Item `initialValue` under Form.List. It always should be configured by Form.List `initialValue` or Form `initialValues`. ## operation @@ -296,7 +296,7 @@ validateFields() #### Rule -Rule support config object, and also support function to get config object: +Rule supports a config object, or a function returning config object: ```tsx type Rule = RuleConfig | ((form: FormInstance) => RuleConfig); @@ -355,7 +355,7 @@ validator(rule, value, callback) => { } ``` -### How does name fill value when it's array? +### How does `name` fill value when it's an array? `name` will fill value by array order. When there exists number in it and no related field in form store, it will auto convert field to array. If you want to keep it as object, use string like: `['1', 'name']`. @@ -373,7 +373,7 @@ Components inside Form.Item with name property will turn into controlled mode, w `ref` only receives the mounted instance. please ref React official doc: -### Why `resetFields` will re-mount component? +### Why will `resetFields` re-mount component? `resetFields` will re-mount component under Field to clean up customize component side effects (like async data, cached state, etc.). It's by design. @@ -384,7 +384,7 @@ In most case, we always recommend to use Form `initialValues`. Use Item `initial 1. Form `initialValues` is the first priority 2. Field `initialValue` is secondary \*. Does not work when multiple Item with same `name` setting the `initialValue` -### Why `onFieldsChange` triggers three times on change when field sets `rules`? +### Why does `onFieldsChange` trigger three times on change when field sets `rules`? Validating is also part of the value updating. It pass follow steps: @@ -394,11 +394,11 @@ Validating is also part of the value updating. It pass follow steps: In each `onFieldsChange`, you will get `false` > `true` > `false` with `isFieldValidating`. -### Why Form.List do not support `label` and need ErrorList to show errors? +### Why doesn't Form.List support `label` and need ErrorList to show errors? Form.List use renderProps which mean internal structure is flexible. Thus `label` and `error` can not have best place. If you want to use antd `label`, you can wrap with Form.Item instead. -### Why Form.Item `dependencies` can not work on Form.List field? +### Why can't Form.Item `dependencies` work on Form.List field? Your name path should also contain Form.List `name`: @@ -417,7 +417,7 @@ Your name path should also contain Form.List `name`: dependencies should be `['users', 0, 'name']` -### Why `normalize` do not support async? +### Why doesn't `normalize` support async? React can not get correct interaction of controlled component with async value update. When user trigger `onChange`, component will do no response since `value` update is async. If you want to trigger value update async, you should use customize component to handle value state internal and pass sync value control to Form instead. diff --git a/components/input-number/index.en-US.md b/components/input-number/index.en-US.md index 76f52d40b0..fc13a9bcb5 100644 --- a/components/input-number/index.en-US.md +++ b/components/input-number/index.en-US.md @@ -25,7 +25,7 @@ When a numeric value needs to be provided. | max | The max value | number | [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) | - | | min | The min value | number | [Number.MIN_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER) | - | | parser | Specifies the value extracted from formatter | function(string): number | - | - | -| precision | The precision of input value | number | - | - | +| precision | The precision of input value. Will use `formatter` when config of `formatter` | number | - | - | | readOnly | If readonly the input | boolean | false | - | | size | The height of input box | `large` \| `middle` \| `small` | - | - | | step | The number to which the current value is increased or decreased. It can be an integer or decimal | number \| string | 1 | - | @@ -37,10 +37,10 @@ When a numeric value needs to be provided. ## Methods -| Name | Description | -| --- | --- | -| blur() | Remove focus | -| focus() | Get focus | +| Name | Description | +| ------- | ------------ | +| blur() | Remove focus | +| focus() | Get focus | ## Notes diff --git a/components/input-number/index.zh-CN.md b/components/input-number/index.zh-CN.md index c1bbbbfa62..ef5266e4e3 100644 --- a/components/input-number/index.zh-CN.md +++ b/components/input-number/index.zh-CN.md @@ -28,7 +28,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg | max | 最大值 | number | [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) | - | | min | 最小值 | number | [Number.MIN_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER) | - | | parser | 指定从 `formatter` 里转换回数字的方式,和 `formatter` 搭配使用 | function(string): number | - | - | -| precision | 数值精度 | number | - | - | +| precision | 数值精度,配置 `formatter` 时会以 `formatter` 为准 | number | - | - | | readOnly | 只读 | boolean | false | - | | size | 输入框大小 | `large` \| `middle` \| `small` | - | - | | step | 每次改变步数,可以为小数 | number \| string | 1 | - | @@ -40,9 +40,9 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg ## 方法 -| 名称 | 描述 | -| --- | --- | -| blur() | 移除焦点 | +| 名称 | 描述 | +| ------- | -------- | +| blur() | 移除焦点 | | focus() | 获取焦点 | ## FAQ diff --git a/components/locale-provider/__tests__/config.test.js b/components/locale-provider/__tests__/config.test.js index 2d9c147f5c..03c58ff791 100644 --- a/components/locale-provider/__tests__/config.test.js +++ b/components/locale-provider/__tests__/config.test.js @@ -11,20 +11,10 @@ import zhCN from '../zh_CN'; class Demo extends React.Component { static defaultProps = {}; - constructor(props) { - super(props); - console.log('constructor', props.type); - } - componentDidMount() { if (this.props.type === 'dashboard') { Modal.confirm({ title: 'Hello World!' }); } - console.log('componentDidMount', this.props.type); - } - - componentWillUnmount() { - console.log('componentWillUnmount', this.props.type); } render() { diff --git a/components/table/demo/edit-row.md b/components/table/demo/edit-row.md index 053070791e..c07f2eb2ee 100644 --- a/components/table/demo/edit-row.md +++ b/components/table/demo/edit-row.md @@ -9,7 +9,7 @@ title: 带行编辑功能的表格。 -> 🛎️ 想要 3 分钟实现?试试 [ProTable 的可编辑表格](https://procomponents.ant.design/components/table#%E5%8F%AF%E7%BC%96%E8%BE%91%E8%A1%A8%E6%A0%BC)! +> 🛎️ 想要 3 分钟实现?试试 [ProTable 的可编辑表格](https://procomponents.ant.design/components/editable-table)! ## en-US diff --git a/components/table/style/index.less b/components/table/style/index.less index a37921e32f..7a42f58cc0 100644 --- a/components/table/style/index.less +++ b/components/table/style/index.less @@ -497,8 +497,13 @@ } // https://github.com/ant-design/ant-design/issues/25573 - .@{descriptions-prefix-cls}-view table { - width: auto; + .@{descriptions-prefix-cls}-view { + display: flex; + + table { + flex: auto; + width: auto; + } } } diff --git a/components/tabs/index.en-US.md b/components/tabs/index.en-US.md index 39386c57ba..cf12178f30 100644 --- a/components/tabs/index.en-US.md +++ b/components/tabs/index.en-US.md @@ -28,7 +28,6 @@ Ant Design has 3 types of Tabs for different situations. | centered | Centers tabs | boolean | false | 4.4.0 | | defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set | string | - | | | hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | false | | -| keyboard | Whether to turn on keyboard navigation | boolean | true | | | renderTabBar | Replace the TabBar | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | | | size | Preset tab bar size | `large` \| `default` \| `small` | `default` | | | tabBarExtraContent | Extra content in tab bar | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 | diff --git a/components/tabs/index.zh-CN.md b/components/tabs/index.zh-CN.md index c9478fad3d..14662b6e7d 100644 --- a/components/tabs/index.zh-CN.md +++ b/components/tabs/index.zh-CN.md @@ -31,7 +31,6 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。 | centered | 标签居中展示 | boolean | false | 4.4.0 | | defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | `第一个面板` | | | hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | | -| keyboard | 开启键盘切换功能 | boolean | true | | | renderTabBar | 替换 TabBar,用于二次封装标签头 | (props: DefaultTabBarProps, DefaultTabBar: React.ComponentClass) => React.ReactElement | - | | | size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | `default` | | | tabBarExtraContent | tab bar 上额外的元素 | ReactNode \| {left?: ReactNode, right?: ReactNode} | - | object: 4.6.0 | diff --git a/components/upload/Upload.tsx b/components/upload/Upload.tsx index efafbaa4ec..4e39446ff7 100644 --- a/components/upload/Upload.tsx +++ b/components/upload/Upload.tsx @@ -14,7 +14,7 @@ import { UploadType, UploadListType, } from './interface'; -import { T, wrapFile, getFileItem, removeFileItem } from './utils'; +import { T, wrapFile, getFileItem, removeFileItem, replaceFileList } from './utils'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import defaultLocale from '../locale/default'; import { ConfigContext } from '../config-provider'; @@ -129,21 +129,14 @@ const InternalUpload: React.ForwardRefRenderFunction = (pr } }); - onInternalChange(filteredFileInfoList[0]?.file, newFileList); + onInternalChange(objectFileList[0], newFileList); }; const onStart = (file: RcFile) => { const targetItem = wrapFile(file); targetItem.status = 'uploading'; - const nextFileList = [...mergedFileList]; - - const fileIndex = nextFileList.findIndex(({ uid }: UploadFile) => uid === targetItem.uid); - if (fileIndex === -1) { - nextFileList.push(targetItem); - } else { - nextFileList[fileIndex] = targetItem; - } + const nextFileList = replaceFileList(targetItem, mergedFileList); onInternalChange(targetItem, nextFileList); }; @@ -156,37 +149,52 @@ const InternalUpload: React.ForwardRefRenderFunction = (pr } catch (e) { /* do nothing */ } - const targetItem = getFileItem(file, mergedFileList); + // removed - if (!targetItem) { + if (!getFileItem(file, mergedFileList)) { return; } + + const targetItem = wrapFile(file); targetItem.status = 'done'; + targetItem.percent = 100; targetItem.response = response; targetItem.xhr = xhr; - onInternalChange(wrapFile(targetItem), [...mergedFileList]); + + const nextFileList = replaceFileList(targetItem, mergedFileList); + + onInternalChange(targetItem, nextFileList); }; const onProgress = (e: { percent: number }, file: UploadFile) => { - const targetItem = getFileItem(file, mergedFileList); // removed - if (!targetItem) { + if (!getFileItem(file, mergedFileList)) { return; } + + const targetItem = wrapFile(file); + targetItem.status = 'uploading'; targetItem.percent = e.percent; - onInternalChange(wrapFile(targetItem), [...mergedFileList], e); + + const nextFileList = replaceFileList(targetItem, mergedFileList); + + onInternalChange(targetItem, nextFileList, e); }; const onError = (error: Error, response: any, file: UploadFile) => { - const targetItem = getFileItem(file, mergedFileList); // removed - if (!targetItem) { + if (!getFileItem(file, mergedFileList)) { return; } + + const targetItem = wrapFile(file); targetItem.error = error; targetItem.response = response; targetItem.status = 'error'; - onInternalChange(wrapFile(targetItem), [...mergedFileList]); + + const nextFileList = replaceFileList(targetItem, mergedFileList); + + onInternalChange(targetItem, nextFileList); }; const handleRemove = (file: UploadFile) => { diff --git a/components/upload/__tests__/upload.test.js b/components/upload/__tests__/upload.test.js index 9c4eeda078..229e3d9302 100644 --- a/components/upload/__tests__/upload.test.js +++ b/components/upload/__tests__/upload.test.js @@ -308,9 +308,7 @@ describe('Upload', () => { it('Proxy support', () => { const file = new File([], 'aaa.zip'); - const copiedFile = wrapFile(file); - console.log(Object.keys(copiedFile)); ['uid', 'lastModified', 'lastModifiedDate', 'name', 'size', 'type'].forEach(key => { expect(key in copiedFile).toBe(true); }); @@ -635,12 +633,12 @@ describe('Upload', () => { switch (callTimes) { case 1: + expect(e.file.originFileObj).toBeTruthy(); expect(file.status).toBe(undefined); break; case 2: case 3: - console.log('===>', file.status); expect(file).toEqual(expect.objectContaining({ status: 'uploading', percent: 0 })); break; diff --git a/components/upload/__tests__/uploadlist.test.js b/components/upload/__tests__/uploadlist.test.js index 7a144cc809..8d7ea6f01c 100644 --- a/components/upload/__tests__/uploadlist.test.js +++ b/components/upload/__tests__/uploadlist.test.js @@ -1045,14 +1045,18 @@ describe('Upload List', () => { it('[deprecated] should support transformFile', done => { let wrapper; + let lastFile; const handleTransformFile = jest.fn(); const onChange = ({ file }) => { if (file.status === 'done') { + expect(file).not.toBe(lastFile); expect(handleTransformFile).toHaveBeenCalled(); wrapper.unmount(); done(); } + + lastFile = file; }; wrapper = mount( , fileList: UploadFile[]) { + const nextFileList = [...fileList]; + const fileIndex = nextFileList.findIndex(({ uid }: UploadFile) => uid === file.uid); + if (fileIndex === -1) { + nextFileList.push(file); + } else { + nextFileList[fileIndex] = file; + } + return nextFileList; +} + export function getFileItem(file: UploadFile, fileList: UploadFile[]) { const matchKey = file.uid !== undefined ? 'uid' : 'name'; return fileList.filter(item => item[matchKey] === file[matchKey])[0]; diff --git a/package.json b/package.json index bd16d20dbc..3ccbb7522a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "4.13.0", + "version": "4.13.1", "description": "An enterprise-class UI design language and React components implementation", "title": "Ant Design", "keywords": [