diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md
index e1137d1e14..d0347c38a6 100644
--- a/CHANGELOG.en-US.md
+++ b/CHANGELOG.en-US.md
@@ -15,6 +15,21 @@ timeline: true
---
+## 4.6.6
+
+`2020-09-27`
+
+- 🐞 Fix Steps first item shifts in small screen. [#26894](https://github.com/ant-design/ant-design/pull/26894)
+- 💄 Fix Divider border style not work when text is provided. [#26863](https://github.com/ant-design/ant-design/pull/26863)
+- 🐞 Fix Radio.Button validation error highlight. [#26849](https://github.com/ant-design/ant-design/pull/26849) [@dhorelik](https://github.com/dhorelik)
+- 💄 Fix Typography link-decoration style. [#26854](https://github.com/ant-design/ant-design/pull/26854) [@vineetvk01](https://github.com/vineetvk01)
+- Locale
+ - 🌐 Add Thai locale support. [#26906](https://github.com/ant-design/ant-design/pull/26906) [@anawinwz](https://github.com/anawinwz)
+- TypeScript
+ - 🤖 Fix message.destroy parameter type. [#26864](https://github.com/ant-design/ant-design/pull/26864) [@lihqi](https://github.com/lihqi)
+ - 🤖 Optimize Slider type definition. [#26884](https://github.com/ant-design/ant-design/pull/26884)
+ - 🤖 Form properly export `FormListProps` type. [#26831](https://github.com/ant-design/ant-design/pull/26831) [@mgcrea](https://github.com/mgcrea)
+
## 4.6.5
`2020-09-20`
diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md
index 40980ba7bf..64f65066b5 100644
--- a/CHANGELOG.zh-CN.md
+++ b/CHANGELOG.zh-CN.md
@@ -15,6 +15,21 @@ timeline: true
---
+## 4.6.6
+
+`2020-09-27`
+
+- 🐞 修复 Steps 在小屏幕下第一项偏移的问题。[#26894](https://github.com/ant-design/ant-design/pull/26894)
+- 💄 修复 Divider 在有文字时,设置边框颜色无效的问题。[#26863](https://github.com/ant-design/ant-design/pull/26863)
+- 🐞 修复 Radio.Button 错误校验高亮样式的问题。[#26849](https://github.com/ant-design/ant-design/pull/26849) [@dhorelik](https://github.com/dhorelik)
+- 💄 修复 Typography 链接下划线样式。[#26854](https://github.com/ant-design/ant-design/pull/26854) [@vineetvk01](https://github.com/vineetvk01)
+- 国际化
+ - 🌐 添加泰语支持。[#26906](https://github.com/ant-design/ant-design/pull/26906) [@anawinwz](https://github.com/anawinwz)
+- TypeScript
+ - 🤖 修复 message.destroy 参数类型错误。[#26864](https://github.com/ant-design/ant-design/pull/26864) [@lihqi](https://github.com/lihqi)
+ - 🤖 优化 Slider 类型定义。[#26884](https://github.com/ant-design/ant-design/pull/26884)
+ - 🤖 导出 Form 中的 `FormListProps` 类型。[#26831](https://github.com/ant-design/ant-design/pull/26831) [@mgcrea](https://github.com/mgcrea)
+
## 4.6.5
`2020-09-20`
diff --git a/components/locale/pl_PL.tsx b/components/locale/pl_PL.tsx
index ac3c2c836c..ec7d2dc2d4 100644
--- a/components/locale/pl_PL.tsx
+++ b/components/locale/pl_PL.tsx
@@ -16,6 +16,9 @@ const localeValues: Locale = {
filterReset: 'Wyczyść',
selectAll: 'Zaznacz bieżącą stronę',
selectInvert: 'Odwróć zaznaczenie',
+ triggerDesc: 'Sortuj rosnąco',
+ triggerAsc: 'Sortuj malejąco',
+ cancelSort: 'Usuń sortowanie',
},
Modal: {
okText: 'OK',
diff --git a/components/message/__tests__/config.test.js b/components/message/__tests__/config.test.js
index e32e82e9e2..4e9ea08856 100644
--- a/components/message/__tests__/config.test.js
+++ b/components/message/__tests__/config.test.js
@@ -1,7 +1,15 @@
import { sleep } from '../../../tests/utils';
-import message from '..';
+import message, { getInstance } from '..';
describe('message.config', () => {
+ // Mock for rc-util raf
+ window.requestAnimationFrame = callback => {
+ return window.setTimeout(callback, 16);
+ };
+ window.cancelAnimationFrame = id => {
+ window.clearTimeout(id);
+ };
+
beforeEach(() => {
jest.useFakeTimers();
});
@@ -47,11 +55,12 @@ describe('message.config', () => {
for (let i = 0; i < 10; i += 1) {
message.info('test');
}
+
message.info('last');
expect(document.querySelectorAll('.ant-message-notice').length).toBe(5);
expect(document.querySelectorAll('.ant-message-notice')[4].textContent).toBe('last');
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
});
it('should be able to config duration', async () => {
@@ -60,8 +69,10 @@ describe('message.config', () => {
duration: 0.5,
});
message.info('last');
+ expect(getInstance().component.state.notices).toHaveLength(1);
+
await sleep(1000);
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
message.config({
duration: 3,
});
diff --git a/components/message/__tests__/hooks.test.js b/components/message/__tests__/hooks.test.js
index 7b452b9cfe..b1d3811b62 100644
--- a/components/message/__tests__/hooks.test.js
+++ b/components/message/__tests__/hooks.test.js
@@ -1,7 +1,7 @@
/* eslint-disable jsx-a11y/control-has-associated-label */
import React from 'react';
import { mount } from 'enzyme';
-import message from '..';
+import message, { getInstance } from '..';
import ConfigProvider from '../../config-provider';
describe('message.hooks', () => {
@@ -171,7 +171,7 @@ describe('message.hooks', () => {
expect(document.querySelectorAll('.my-test-message-notice').length).toBe(1);
hide();
jest.runAllTimers();
- expect(document.querySelectorAll('.my-test-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
});
it('should be same hook', () => {
diff --git a/components/message/__tests__/index.test.js b/components/message/__tests__/index.test.js
index b91b26dc00..cb8d4d14c0 100644
--- a/components/message/__tests__/index.test.js
+++ b/components/message/__tests__/index.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { SmileOutlined } from '@ant-design/icons';
-import message from '..';
+import message, { getInstance } from '..';
describe('message', () => {
beforeEach(() => {
@@ -19,10 +19,10 @@ describe('message', () => {
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
hide1();
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
+ expect(getInstance().component.state.notices).toHaveLength(1);
hide2();
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
});
it('should be able to remove manually with a unique key', () => {
@@ -33,10 +33,10 @@ describe('message', () => {
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
message.destroy(key1);
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
+ expect(getInstance().component.state.notices).toHaveLength(1);
message.destroy(key2);
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
});
it('should be able to destroy globally', () => {
@@ -93,7 +93,7 @@ describe('message', () => {
expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
hide();
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
});
it('should allow custom icon', () => {
@@ -169,7 +169,7 @@ describe('message', () => {
mount();
expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
jest.advanceTimersByTime(1500);
- expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
+ expect(getInstance().component.state.notices).toHaveLength(0);
});
it('should not throw error when pass null', () => {
diff --git a/components/message/index.tsx b/components/message/index.tsx
index 5367ab5df1..e58344b0d3 100755
--- a/components/message/index.tsx
+++ b/components/message/index.tsx
@@ -193,7 +193,7 @@ function isArgsProps(content: JointContent): content is ArgsProps {
const api: any = {
open: notice,
config: setMessageConfig,
- destroy(messageKey?: number | string) {
+ destroy(messageKey?: React.Key) {
if (messageInstance) {
if (messageKey) {
const { removeNotice } = messageInstance;
@@ -243,8 +243,13 @@ export interface MessageInstance {
export interface MessageApi extends MessageInstance {
warn(content: JointContent, duration?: ConfigDuration, onClose?: ConfigOnClose): MessageType;
config(options: ConfigOptions): void;
- destroy(): void;
+ destroy(messageKey?: React.Key): void;
useMessage(): [MessageInstance, React.ReactElement];
}
+/** @private test only function. Not work on production */
+export const getInstance = () => {
+ return process.env.NODE_ENV === 'test' ? messageInstance : null;
+};
+
export default api as MessageApi;
diff --git a/components/notification/__tests__/index.test.js b/components/notification/__tests__/index.test.js
index 518aac9e26..6b17f3fc8d 100644
--- a/components/notification/__tests__/index.test.js
+++ b/components/notification/__tests__/index.test.js
@@ -1,18 +1,15 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { UserOutlined } from '@ant-design/icons';
-import notification from '..';
+import notification, { getInstance } from '..';
describe('notification', () => {
- beforeAll(() => {
+ beforeEach(() => {
jest.useFakeTimers();
});
- afterAll(() => {
- jest.useRealTimers();
- });
-
afterEach(() => {
+ jest.useRealTimers();
notification.destroy();
});
@@ -54,14 +51,18 @@ describe('notification', () => {
await Promise.resolve();
expect(document.querySelectorAll('.ant-notification-notice').length).toBe(2);
+
notification.close('1');
- await Promise.resolve();
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-notification-notice').length).toBe(1);
+ expect((await getInstance('ant-notification-topRight')).component.state.notices).toHaveLength(
+ 1,
+ );
+
notification.close('2');
- await Promise.resolve();
jest.runAllTimers();
- expect(document.querySelectorAll('.ant-notification-notice').length).toBe(0);
+ expect((await getInstance('ant-notification-topRight')).component.state.notices).toHaveLength(
+ 0,
+ );
});
it('should be able to destroy globally', async () => {
diff --git a/components/notification/index.tsx b/components/notification/index.tsx
index d772908640..c38ea8acb9 100755
--- a/components/notification/index.tsx
+++ b/components/notification/index.tsx
@@ -280,4 +280,9 @@ export interface NotificationApi extends NotificationInstance {
useNotification: () => [NotificationInstance, React.ReactElement];
}
+/** @private test only function. Not work on production */
+export const getInstance = async (cacheKey: string) => {
+ return process.env.NODE_ENV === 'test' ? notificationInstance[cacheKey] : null;
+};
+
export default api as NotificationApi;
diff --git a/components/slider/index.tsx b/components/slider/index.tsx
index 95121dd936..a8363f2824 100644
--- a/components/slider/index.tsx
+++ b/components/slider/index.tsx
@@ -1,7 +1,5 @@
import * as React from 'react';
-import RcSlider from 'rc-slider/lib/Slider';
-import RcRange from 'rc-slider/lib/Range';
-import RcHandle from 'rc-slider/lib/Handle';
+import RcSlider, { Range as RcRange, Handle as RcHandle } from 'rc-slider';
import classNames from 'classnames';
import { TooltipPlacement } from '../tooltip';
import SliderTooltip from './SliderTooltip';
@@ -18,16 +16,15 @@ export interface SliderMarks {
interface HandleGeneratorInfo {
value?: number;
- dragging: boolean;
+ dragging?: boolean;
index: number;
- rest: any[];
}
export type HandleGeneratorFn = (config: {
tooltipPrefixCls?: string;
prefixCls?: string;
info: HandleGeneratorInfo;
-}) => React.ReactNode;
+}) => React.ReactElement;
export interface SliderBaseProps {
prefixCls?: string;
@@ -35,7 +32,7 @@ export interface SliderBaseProps {
reverse?: boolean;
min?: number;
max?: number;
- step?: number | null;
+ step?: number;
marks?: SliderMarks;
dots?: boolean;
included?: boolean;
@@ -70,81 +67,98 @@ export interface SliderRangeProps extends SliderBaseProps {
export type Visibles = { [index: number]: boolean };
-const Slider = React.forwardRef((props, ref) => {
- const { getPrefixCls, direction, getPopupContainer } = React.useContext(ConfigContext);
- const [visibles, setVisibles] = React.useState({});
+const Slider = React.forwardRef(
+ (props, ref: any) => {
+ const { getPrefixCls, direction, getPopupContainer } = React.useContext(ConfigContext);
+ const [visibles, setVisibles] = React.useState({});
- const toggleTooltipVisible = (index: number, visible: boolean) => {
- setVisibles((prev: Visibles) => {
- return { ...prev, [index]: visible };
- });
- };
+ const toggleTooltipVisible = (index: number, visible: boolean) => {
+ setVisibles((prev: Visibles) => {
+ return { ...prev, [index]: visible };
+ });
+ };
- const getTooltipPlacement = (tooltipPlacement?: TooltipPlacement, vertical?: boolean) => {
- if (tooltipPlacement) {
- return tooltipPlacement;
- }
- if (!vertical) {
- return 'top';
- }
- return direction === 'rtl' ? 'left' : 'right';
- };
+ const getTooltipPlacement = (tooltipPlacement?: TooltipPlacement, vertical?: boolean) => {
+ if (tooltipPlacement) {
+ return tooltipPlacement;
+ }
+ if (!vertical) {
+ return 'top';
+ }
+ return direction === 'rtl' ? 'left' : 'right';
+ };
+
+ const handleWithTooltip: HandleGeneratorFn = ({
+ tooltipPrefixCls,
+ prefixCls,
+ info: { value, dragging, index, ...restProps },
+ }) => {
+ const {
+ tipFormatter,
+ tooltipVisible,
+ tooltipPlacement,
+ getTooltipPopupContainer,
+ vertical,
+ } = props;
+ const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
+ const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
+ return (
+ document.body)}
+ >
+ toggleTooltipVisible(index, true)}
+ onMouseLeave={() => toggleTooltipVisible(index, false)}
+ />
+
+ );
+ };
- const handleWithTooltip: HandleGeneratorFn = ({
- tooltipPrefixCls,
- prefixCls,
- info: { value, dragging, index, ...restProps },
- }) => {
const {
- tipFormatter,
- tooltipVisible,
- tooltipPlacement,
- getTooltipPopupContainer,
- vertical,
+ prefixCls: customizePrefixCls,
+ tooltipPrefixCls: customizeTooltipPrefixCls,
+ range,
+ className,
+ ...restProps
} = props;
- const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
- const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
- return (
- document.body)}
- >
- toggleTooltipVisible(index, true)}
- onMouseLeave={() => toggleTooltipVisible(index, false)}
+ const prefixCls = getPrefixCls('slider', customizePrefixCls);
+ const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
+ const cls = classNames(className, {
+ [`${prefixCls}-rtl`]: direction === 'rtl',
+ });
+ // make reverse default on rtl direction
+ if (direction === 'rtl' && !restProps.vertical) {
+ restProps.reverse = !restProps.reverse;
+ }
+ if (range) {
+ return (
+
+ handleWithTooltip({
+ tooltipPrefixCls,
+ prefixCls,
+ info,
+ })
+ }
+ prefixCls={prefixCls}
/>
-
- );
- };
-
- const {
- prefixCls: customizePrefixCls,
- tooltipPrefixCls: customizeTooltipPrefixCls,
- range,
- className,
- ...restProps
- } = props;
- const prefixCls = getPrefixCls('slider', customizePrefixCls);
- const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
- const cls = classNames(className, {
- [`${prefixCls}-rtl`]: direction === 'rtl',
- });
- // make reverse default on rtl direction
- if (direction === 'rtl' && !restProps.vertical) {
- restProps.reverse = !restProps.reverse;
- }
- if (range) {
+ );
+ }
return (
-
@@ -155,27 +169,10 @@ const Slider = React.forwardRef((
})
}
prefixCls={prefixCls}
- tooltipPrefixCls={tooltipPrefixCls}
/>
);
- }
- return (
-
- handleWithTooltip({
- tooltipPrefixCls,
- prefixCls,
- info,
- })
- }
- prefixCls={prefixCls}
- tooltipPrefixCls={tooltipPrefixCls}
- />
- );
-});
+ },
+);
Slider.displayName = 'Slider';
diff --git a/components/steps/style/vertical.less b/components/steps/style/vertical.less
index d9c87bbc52..cc316946df 100644
--- a/components/steps/style/vertical.less
+++ b/components/steps/style/vertical.less
@@ -4,7 +4,9 @@
.@{steps-prefix-cls}-item {
display: block;
flex: 1 0 auto;
+ padding-left: 0;
overflow: visible;
+
&-icon {
float: left;
margin-right: @steps-vertical-icon-width;
diff --git a/index.js b/index.js
index 465ade6fd6..0a58333efa 100644
--- a/index.js
+++ b/index.js
@@ -1,5 +1,5 @@
/* eslint no-console:0 */
-function camelCase(name) {
+function pascalCase(name) {
return name.charAt(0).toUpperCase() + name.slice(1).replace(/-(\w)/g, (m, n) => n.toUpperCase());
}
@@ -17,7 +17,7 @@ req.keys().forEach(mod => {
// message & notification should not be capitalized
exports[match[1]] = v;
} else {
- exports[camelCase(match[1])] = v;
+ exports[pascalCase(match[1])] = v;
}
}
});
diff --git a/package.json b/package.json
index b32f66b1f4..332217bc00 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "antd",
- "version": "4.6.5",
+ "version": "4.6.6",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
"keywords": [
@@ -129,15 +129,15 @@
"rc-input-number": "~6.0.0",
"rc-mentions": "~1.5.0",
"rc-menu": "~8.7.1",
- "rc-motion": "^2.0.0",
- "rc-notification": "~4.4.0",
+ "rc-motion": "^2.2.0",
+ "rc-notification": "~4.5.2",
"rc-pagination": "~3.0.3",
"rc-picker": "~2.2.1",
"rc-progress": "~3.1.0",
"rc-rate": "~2.8.2",
"rc-resize-observer": "^0.2.3",
"rc-select": "~11.3.2",
- "rc-slider": "~9.4.1",
+ "rc-slider": "~9.5.1",
"rc-steps": "~4.1.0",
"rc-switch": "~3.2.0",
"rc-table": "~7.9.2",
@@ -195,7 +195,7 @@
"enquire-js": "^0.2.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
- "enzyme-to-json": "^3.3.5",
+ "enzyme-to-json": "^3.6.0",
"esbuild-webpack-plugin": "^1.0.0",
"eslint": "^7.9.0",
"eslint-config-airbnb": "^18.0.0",
diff --git a/typings/custom-typings.d.ts b/typings/custom-typings.d.ts
index 6a302f4c67..809a080bfd 100644
--- a/typings/custom-typings.d.ts
+++ b/typings/custom-typings.d.ts
@@ -46,14 +46,6 @@ declare module 'rc-rate';
declare module 'rc-queue-anim';
-declare module 'rc-slider';
-
-declare module 'rc-slider/lib/Slider';
-
-declare module 'rc-slider/lib/Range';
-
-declare module 'rc-slider/lib/Handle';
-
declare module 'rc-steps';
declare module 'rc-switch';