diff --git a/.github/workflows/release-helper.yml b/.github/workflows/release-helper.yml index d53ea4b21a..66d96a6e6b 100644 --- a/.github/workflows/release-helper.yml +++ b/.github/workflows/release-helper.yml @@ -27,3 +27,16 @@ jobs: msg-footer: '💬 前往 [**Ant Design Releases**]({{url}}) 查看更新日志' prettier: true prerelease-filter: '-, a, b, A, B' + + - name: make release - Bigfish + uses: actions-cool/release-helper@v1 + with: + triger: 'tag' + changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md' + branch: 'master' + dingding-token: ${{ secrets.DINGDING_BOT_BIGFISH_TOKEN }} + dingding-msg: 'CHANGELOG.zh-CN.md' + msg-poster: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ' + msg-footer: '💬 前往 [**Ant Design Releases**]({{url}}) 查看更新日志' + prettier: true + prerelease-filter: '-, a, b, A, B' diff --git a/components/card/__tests__/index.test.js b/components/card/__tests__/index.test.js index 8e1cade399..da9a0979c0 100644 --- a/components/card/__tests__/index.test.js +++ b/components/card/__tests__/index.test.js @@ -82,4 +82,22 @@ describe('Card', () => { ); expect(wrapper.find('Tabs').get(0).props.size).toBe('small'); }); + + it('get ref of card', () => { + class WrapperComponent extends React.Component { + render() { + return ( + +

Card content

+
+ ); + } + } + const wrapper = mount(); + expect(wrapper.ref('firstRef').className.includes('ant-card')).toBe(true); + }); }); diff --git a/components/card/index.tsx b/components/card/index.tsx index 983eb92c89..b4b39ac0db 100644 --- a/components/card/index.tsx +++ b/components/card/index.tsx @@ -56,12 +56,12 @@ export interface CardProps extends Omit, 't tabProps?: TabsProps; } -export interface CardInterface extends React.FC { +export interface CardInterface extends React.ForwardRefExoticComponent { Grid: typeof Grid; Meta: typeof Meta; } -const Card: CardInterface = props => { +const Card = React.forwardRef((props: CardProps, ref: React.Ref) => { const { getPrefixCls, direction } = React.useContext(ConfigContext); const size = React.useContext(SizeContext); @@ -196,14 +196,14 @@ const Card: CardInterface = props => { ); return ( -
+
{head} {coverDom} {body} {actionDom}
); -}; +}) as CardInterface; Card.Grid = Grid; Card.Meta = Meta; diff --git a/components/cascader/__tests__/index.test.js b/components/cascader/__tests__/index.test.js index 41ac07d339..310b6b76ee 100644 --- a/components/cascader/__tests__/index.test.js +++ b/components/cascader/__tests__/index.test.js @@ -492,6 +492,12 @@ describe('Cascader', () => { expect(onChange).toHaveBeenCalledWith(['Zhejiang', 'Hangzhou', 'West Lake'], expect.anything()); }); + it('rtl should work well with placement', () => { + const wrapper = mount(); + + expect(wrapper.find('Trigger').prop('popupPlacement')).toEqual('bottomRight'); + }); + describe('legacy props', () => { it('popupClassName', () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index 9563b7f682..718619deee 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -10,7 +10,7 @@ import type { } from 'rc-cascader'; import omit from 'rc-util/lib/omit'; import RightOutlined from '@ant-design/icons/RightOutlined'; -import RedoOutlined from '@ant-design/icons/RedoOutlined'; +import LoadingOutlined from '@ant-design/icons/LoadingOutlined'; import LeftOutlined from '@ant-design/icons/LeftOutlined'; import devWarning from '../_util/devWarning'; import { ConfigContext } from '../config-provider'; @@ -194,7 +194,7 @@ const Cascader = React.forwardRef((props: CascaderProps, ref: React.Ref - + ); diff --git a/components/checkbox/Checkbox.tsx b/components/checkbox/Checkbox.tsx index a4df83fd0d..8834aed75a 100644 --- a/components/checkbox/Checkbox.tsx +++ b/components/checkbox/Checkbox.tsx @@ -78,6 +78,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction checkboxGroup?.cancelValue(restProps.value); }, [restProps.value]); diff --git a/components/checkbox/__tests__/group.test.js b/components/checkbox/__tests__/group.test.js index b944b5bce8..8d7059ffcc 100644 --- a/components/checkbox/__tests__/group.test.js +++ b/components/checkbox/__tests__/group.test.js @@ -1,10 +1,11 @@ -import React from 'react'; +import React, { useState } from 'react'; import { mount, render } from 'enzyme'; import Collapse from '../../collapse'; import Table from '../../table'; import Checkbox from '../index'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; +import Input from '../../input'; describe('CheckboxGroup', () => { mountTest(Checkbox.Group); @@ -222,4 +223,40 @@ describe('CheckboxGroup', () => { wrapper.find('.ant-checkbox-input').at(0).simulate('change'); expect(onChange).toHaveBeenCalledWith([1]); }); + + it('should store latest checkbox value if changed', () => { + const onChange = jest.fn(); + + const Demo = () => { + const [v, setV] = useState(''); + + React.useEffect(() => { + setTimeout(setV('1'), 1000); + }, []); + + return ( +
+ setV(e.target.value)} /> + + + A + + +
+ ); + }; + + const wrapper = mount(); + + wrapper.find('.ant-checkbox-input').first().simulate('change'); + expect(onChange).toHaveBeenCalledWith([]); + wrapper.find('.ant-checkbox-input').first().simulate('change'); + expect(onChange).toHaveBeenCalledWith(['length1']); + wrapper + .find('.ant-input') + .first() + .simulate('change', { target: { value: '' } }); + wrapper.find('.ant-checkbox-input').first().simulate('change'); + expect(onChange).toHaveBeenCalledWith(['A']); + }); }); diff --git a/components/checkbox/style/mixin.less b/components/checkbox/style/mixin.less index 60c8201a5e..c16a3f091a 100644 --- a/components/checkbox/style/mixin.less +++ b/components/checkbox/style/mixin.less @@ -122,6 +122,7 @@ .@{checkbox-prefix-cls}-input { cursor: not-allowed; + pointer-events: none; } .@{checkbox-inner-prefix-cls} { diff --git a/components/style/themes/dark.less b/components/style/themes/dark.less index 00ec8c7bdd..59a9b69f20 100644 --- a/components/style/themes/dark.less +++ b/components/style/themes/dark.less @@ -320,6 +320,17 @@ @table-filter-dropdown-bg: @popover-background; @table-expand-icon-bg: transparent; +// Tag +// --- +@info-color-deprecated-bg: @primary-1; +@info-color-deprecated-border: @primary-3; +@success-color-deprecated-bg: @green-1; +@success-color-deprecated-border: @green-3; +@warning-color-deprecated-bg: @orange-1; +@warning-color-deprecated-border: @orange-3; +@error-color-deprecated-bg: @red-1; +@error-color-deprecated-border: @red-3; + // TimePicker // --- @picker-basic-cell-hover-with-range-color: darken(@primary-color, 35%); diff --git a/components/tooltip/__tests__/__snapshots__/tooltip.test.js.snap b/components/tooltip/__tests__/__snapshots__/tooltip.test.js.snap index 718c3d35ee..776998c5f7 100644 --- a/components/tooltip/__tests__/__snapshots__/tooltip.test.js.snap +++ b/components/tooltip/__tests__/__snapshots__/tooltip.test.js.snap @@ -16,32 +16,6 @@ exports[`Tooltip should hide when mouse leave antd disabled component Button 1`] `; -exports[`Tooltip should hide when mouse leave antd disabled component Checkbox 1`] = ` - - - -`; - exports[`Tooltip should hide when mouse leave antd disabled component Switch 1`] = ` { testComponent('Button', Button); testComponent('Switch', Switch); - testComponent('Checkbox', Checkbox); }); it('should render disabled Button style properly', () => { diff --git a/components/tooltip/index.tsx b/components/tooltip/index.tsx index 93a53eef7c..0e8b6e0562 100644 --- a/components/tooltip/index.tsx +++ b/components/tooltip/index.tsx @@ -87,7 +87,6 @@ function getDisabledCompatibleChildren(element: React.ReactElement, prefixC if ( (elementType.__ANT_BUTTON === true || elementType.__ANT_SWITCH === true || - elementType.__ANT_CHECKBOX === true || element.type === 'button') && element.props.disabled ) { diff --git a/components/typography/index.en-US.md b/components/typography/index.en-US.md index a8b897c5fe..58796086c4 100644 --- a/components/typography/index.en-US.md +++ b/components/typography/index.en-US.md @@ -144,3 +144,5 @@ Basic text writing, including headings, body text, lists, and more. ```tsx ``` + +**Note:** This is not equivalent to the execution logic of react-router's Link [reference](https://github.com/ant-design/ant-design/pull/26737/files#r488769888) diff --git a/components/typography/index.zh-CN.md b/components/typography/index.zh-CN.md index 26b9253f25..1a1fdaa9dc 100644 --- a/components/typography/index.zh-CN.md +++ b/components/typography/index.zh-CN.md @@ -145,3 +145,5 @@ cover: https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg ```tsx ``` + +**注意:** 这并不是和 react-router 的 Link 的执行逻辑等价 [参考](https://github.com/ant-design/ant-design/pull/26737/files#r488769888) diff --git a/docs/react/contributing.en-US.md b/docs/react/contributing.en-US.md index 0c19b32572..6788342897 100644 --- a/docs/react/contributing.en-US.md +++ b/docs/react/contributing.en-US.md @@ -79,6 +79,8 @@ Use `DEV_THEME` to change start theme: DEV_THEME=dark npm start ``` +Visit [http://127.0.0.1:8001/components/button-cn/?theme=dark](http://127.0.0.1:8001/components/button-cn/?theme=dark). + ## Being a collaborator If you are an active contributor and are willing to work with Ant Design Team in our opensource workflow, you can [apply to be a outside collaborator](https://github.com/ant-design/ant-design/wiki/Collaborators#how-to-apply-for-being-a-collaborator). diff --git a/docs/react/contributing.zh-CN.md b/docs/react/contributing.zh-CN.md index 7d73e8b486..14a9aeecd6 100644 --- a/docs/react/contributing.zh-CN.md +++ b/docs/react/contributing.zh-CN.md @@ -79,6 +79,8 @@ Ant Design 团队会关注所有的 pull request,我们会 review 以及合并 DEV_THEME=dark npm start ``` +访问 [http://127.0.0.1:8001/components/button-cn/?theme=dark](http://127.0.0.1:8001/components/button-cn/?theme=dark)。 + ## 加入社区 如果你贡献度足够活跃,希望和 Ant Design 团队一起参与维护工作,你可以[申请成为社区协作者](https://github.com/ant-design/ant-design/wiki/Collaborators#how-to-apply-for-being-a-collaborator)。 diff --git a/package.json b/package.json index c16daee555..dd3c5863ba 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "pretty-quick": "pretty-quick", "pub": "npm run version && antd-tools run pub", "prepublishOnly": "antd-tools run guard", + "postpublish": "node ./scripts/post-script.js", "site:theme": "npm run site:theme-dark && npm run site:theme-compact", "site:theme-dark": "cross-env ESBUILD=1 ANT_THEME=dark bisheng build -c ./site/bisheng.config.js", "site:theme-compact": "cross-env ESBUILD=1 ANT_THEME=compact bisheng build -c ./site/bisheng.config.js", @@ -120,7 +121,7 @@ "lodash": "^4.17.21", "memoize-one": "^6.0.0", "moment": "^2.25.3", - "rc-cascader": "~3.0.0-alpha.8", + "rc-cascader": "~3.2.1", "rc-checkbox": "~2.3.0", "rc-collapse": "~3.1.0", "rc-dialog": "~8.6.0", @@ -147,7 +148,7 @@ "rc-textarea": "~0.3.0", "rc-tooltip": "~5.1.1", "rc-tree": "~5.4.3", - "rc-tree-select": "~5.1.0", + "rc-tree-select": "~5.1.1", "rc-trigger": "^5.2.10", "rc-upload": "~4.3.0", "rc-util": "^5.14.0", @@ -270,6 +271,7 @@ "remove-files-webpack-plugin": "^1.4.5", "rimraf": "^3.0.0", "scrollama": "^3.0.0", + "semver": "^7.3.5", "simple-git": "^2.23.0", "string-replace-loader": "^3.0.3", "stylelint": "^14.0.0", diff --git a/scripts/post-script.js b/scripts/post-script.js new file mode 100644 index 0000000000..2f8c50a638 --- /dev/null +++ b/scripts/post-script.js @@ -0,0 +1,87 @@ +const fetch = require('isomorphic-fetch'); +const semver = require('semver'); +const moment = require('moment'); +const inquirer = require('inquirer'); +const chalk = require('chalk'); +const { spawnSync } = require('child_process'); + +const SAFE_DAYS_START = 1000 * 60 * 60 * 24 * 15; // 15 days +const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be stable + +(async function process() { + console.log(chalk.cyan('🤖 Post Publish Scripting...\n')); + const { time, 'dist-tags': distTags } = await fetch('http://registry.npmjs.org/antd').then(res => + res.json(), + ); + + console.log('🐚 Latest Conch Version:', chalk.green(distTags.conch || 'null'), '\n'); + + // Sort and get the latest versions + const versionList = Object.keys(time) + .filter(version => semver.valid(version) && !semver.prerelease(version)) + .sort((v1, v2) => { + const time1 = moment(time[v1]).valueOf(); + const time2 = moment(time[v2]).valueOf(); + + return time2 - time1; + }); + + // Slice for choosing the latest versions + const latestVersions = versionList.slice(0, 20).map(version => ({ + publishTime: time[version], + timeDiff: moment().diff(moment(time[version])), + value: version, + })); + + const startDefaultVersionIndex = latestVersions.findIndex( + ({ timeDiff }) => timeDiff >= SAFE_DAYS_START, + ); + const defaultVersionList = latestVersions.slice(0, startDefaultVersionIndex + 1).reverse(); + + // Find safe version + let defaultVersionObj; + for (let i = 0; i < defaultVersionList.length - 1; i += 1) { + defaultVersionObj = defaultVersionList[i]; + const nextVersionObj = defaultVersionList[i + 1]; + + if (defaultVersionObj.timeDiff - nextVersionObj.timeDiff > SAFE_DAYS_DIFF) { + break; + } + + defaultVersionObj = null; + } + + // Not find to use the latest version instead + defaultVersionObj = defaultVersionObj || defaultVersionList[defaultVersionList.length - 1]; + const defaultVersion = defaultVersionObj ? defaultVersionObj.value : null; + + // Selection + const { conchVersion } = await inquirer.prompt([ + { + type: 'list', + name: 'conchVersion', + default: defaultVersion, + message: 'Please select Conch Version:', + choices: latestVersions.map(info => { + const { value, publishTime } = info; + const desc = moment(publishTime).fromNow(); + + return { + ...info, + name: `${value} (${desc}) ${value === defaultVersion ? '(default)' : ''}`, + }; + }), + }, + ]); + + // Check if need to update + if (distTags.conch === conchVersion) { + console.log(`🎃 Conch Version not change. Safe to ${chalk.green('ignore')}.`); + } else { + console.log('💾 Tagging Conch Version:', chalk.green(conchVersion)); + spawnSync('npm', ['dist-tag', 'add', `antd@${conchVersion}`, 'conch'], { + stdio: 'inherit', + stdin: 'inherit', + }); + } +})();