mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 13:09:40 +08:00
commit
0c6d1512be
13
.github/workflows/release-helper.yml
vendored
13
.github/workflows/release-helper.yml
vendored
@ -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'
|
||||
|
@ -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
|
||||
// eslint-disable-next-line react/no-string-refs
|
||||
ref="firstRef"
|
||||
title="Card title"
|
||||
>
|
||||
<p>Card content</p>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
const wrapper = mount(<WrapperComponent />);
|
||||
expect(wrapper.ref('firstRef').className.includes('ant-card')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -56,12 +56,12 @@ export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 't
|
||||
tabProps?: TabsProps;
|
||||
}
|
||||
|
||||
export interface CardInterface extends React.FC<CardProps> {
|
||||
export interface CardInterface extends React.ForwardRefExoticComponent<CardProps> {
|
||||
Grid: typeof Grid;
|
||||
Meta: typeof Meta;
|
||||
}
|
||||
|
||||
const Card: CardInterface = props => {
|
||||
const Card = React.forwardRef((props: CardProps, ref: React.Ref<HTMLDivElement>) => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const size = React.useContext(SizeContext);
|
||||
|
||||
@ -196,14 +196,14 @@ const Card: CardInterface = props => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div {...divProps} className={classString}>
|
||||
<div ref={ref} {...divProps} className={classString}>
|
||||
{head}
|
||||
{coverDom}
|
||||
{body}
|
||||
{actionDom}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}) as CardInterface;
|
||||
|
||||
Card.Grid = Grid;
|
||||
Card.Meta = Meta;
|
||||
|
@ -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(<Cascader options={options} direction="rtl" />);
|
||||
|
||||
expect(wrapper.find('Trigger').prop('popupPlacement')).toEqual('bottomRight');
|
||||
});
|
||||
|
||||
describe('legacy props', () => {
|
||||
it('popupClassName', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
@ -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<any>, ref: React.Ref<Cas
|
||||
|
||||
const loadingIcon = (
|
||||
<span className={`${prefixCls}-menu-item-loading-icon`}>
|
||||
<RedoOutlined spin />
|
||||
<LoadingOutlined spin />
|
||||
</span>
|
||||
);
|
||||
|
||||
|
@ -78,6 +78,7 @@ const InternalCheckbox: React.ForwardRefRenderFunction<HTMLInputElement, Checkbo
|
||||
if (restProps.value !== prevValue.current) {
|
||||
checkboxGroup?.cancelValue(prevValue.current);
|
||||
checkboxGroup?.registerValue(restProps.value);
|
||||
prevValue.current = restProps.value;
|
||||
}
|
||||
return () => checkboxGroup?.cancelValue(restProps.value);
|
||||
}, [restProps.value]);
|
||||
|
@ -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 (
|
||||
<div>
|
||||
<Input className="my-input" value={v} onChange={e => setV(e.target.value)} />
|
||||
<Checkbox.Group defaultValue={['length1']} style={{ width: '100%' }} onChange={onChange}>
|
||||
<Checkbox className="target-checkbox" value={v ? `length${v}` : 'A'}>
|
||||
A
|
||||
</Checkbox>
|
||||
</Checkbox.Group>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
|
||||
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']);
|
||||
});
|
||||
});
|
||||
|
@ -122,6 +122,7 @@
|
||||
|
||||
.@{checkbox-prefix-cls}-input {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.@{checkbox-inner-prefix-cls} {
|
||||
|
@ -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%);
|
||||
|
@ -16,32 +16,6 @@ exports[`Tooltip should hide when mouse leave antd disabled component Button 1`]
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`Tooltip should hide when mouse leave antd disabled component Checkbox 1`] = `
|
||||
<span
|
||||
class="ant-tooltip-disabled-compatible-wrapper"
|
||||
style="display: inline-block; cursor: not-allowed;"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled"
|
||||
style="pointer-events: none;"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-checkbox-disabled"
|
||||
>
|
||||
<input
|
||||
class="ant-checkbox-input"
|
||||
disabled=""
|
||||
type="checkbox"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-checkbox-inner"
|
||||
/>
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`Tooltip should hide when mouse leave antd disabled component Switch 1`] = `
|
||||
<span
|
||||
class="ant-tooltip-disabled-compatible-wrapper"
|
||||
|
@ -4,7 +4,6 @@ import { spyElementPrototype } from 'rc-util/lib/test/domHook';
|
||||
import Tooltip from '..';
|
||||
import Button from '../../button';
|
||||
import Switch from '../../switch';
|
||||
import Checkbox from '../../checkbox';
|
||||
import DatePicker from '../../date-picker';
|
||||
import Input from '../../input';
|
||||
import Group from '../../input/Group';
|
||||
@ -131,7 +130,6 @@ describe('Tooltip', () => {
|
||||
|
||||
testComponent('Button', Button);
|
||||
testComponent('Switch', Switch);
|
||||
testComponent('Checkbox', Checkbox);
|
||||
});
|
||||
|
||||
it('should render disabled Button style properly', () => {
|
||||
|
@ -87,7 +87,6 @@ function getDisabledCompatibleChildren(element: React.ReactElement<any>, prefixC
|
||||
if (
|
||||
(elementType.__ANT_BUTTON === true ||
|
||||
elementType.__ANT_SWITCH === true ||
|
||||
elementType.__ANT_CHECKBOX === true ||
|
||||
element.type === 'button') &&
|
||||
element.props.disabled
|
||||
) {
|
||||
|
@ -144,3 +144,5 @@ Basic text writing, including headings, body text, lists, and more.
|
||||
```tsx
|
||||
<Link to="/" component={Typography.Link} />
|
||||
```
|
||||
|
||||
**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)
|
||||
|
@ -145,3 +145,5 @@ cover: https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg
|
||||
```tsx
|
||||
<Link to="/" component={Typography.Link} />
|
||||
```
|
||||
|
||||
**注意:** 这并不是和 react-router 的 Link 的执行逻辑等价 [参考](https://github.com/ant-design/ant-design/pull/26737/files#r488769888)
|
||||
|
@ -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).
|
||||
|
@ -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)。
|
||||
|
@ -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",
|
||||
|
87
scripts/post-script.js
Normal file
87
scripts/post-script.js
Normal file
@ -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',
|
||||
});
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user