Browse Source

Merge pull request #30870 from ant-design/master-to-merge-feature

chore: merge master into feature
pull/30902/head
afc163 4 years ago
committed by GitHub
parent
commit
2e65f276de
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      CHANGELOG.en-US.md
  2. 18
      CHANGELOG.zh-CN.md
  3. 86
      components/dropdown/style/index.less
  4. 2
      components/empty/index.en-US.md
  5. 2
      components/empty/index.zh-CN.md
  6. 2
      components/form/Form.tsx
  7. 6
      components/form/hooks/useForm.ts
  8. 18
      components/input/Input.tsx
  9. 144
      components/layout/__tests__/__snapshots__/demo.test.js.snap
  10. 7
      components/layout/demo/top.md
  11. 25
      components/locale-provider/LocaleReceiver.tsx
  12. 14
      components/locale-provider/index.tsx
  13. 9
      components/menu/style/index.less
  14. 6
      components/page-header/index.tsx
  15. 24
      components/progress/Circle.tsx
  16. 180
      components/progress/__tests__/__snapshots__/demo.test.js.snap
  17. 48
      components/progress/__tests__/__snapshots__/index.test.js.snap
  18. 10
      components/progress/__tests__/index.test.js
  19. 5
      components/progress/progress.tsx
  20. 60
      components/steps/__tests__/__snapshots__/demo.test.js.snap
  21. 68
      components/table/__tests__/Table.rowSelection.test.js
  22. 40
      components/table/hooks/useSelection.tsx
  23. 8
      components/table/style/index.less
  24. 1
      components/tooltip/style/index.less
  25. 31
      components/typography/Base.tsx
  26. 197
      components/typography/__tests__/copy.test.tsx
  27. 9
      components/typography/util.tsx
  28. 6
      docs/react/replace-moment.zh-CN.md
  29. 6
      package.json
  30. 25
      site/theme/template/Home/RecommendPage.less

18
CHANGELOG.en-US.md

@ -15,6 +15,24 @@ timeline: true
---
## 4.16.2
`2021-06-07`
- 🐞 Fix Menu auto overflow with `horizontal` mod breaks by `float` element. [#30879](https://github.com/ant-design/ant-design/pull/30879)
- Typography
- 🐞 Fix the problem that Typography.Paragraph `copyable` will treat `React.Fragment` as an array. [#30869](https://github.com/ant-design/ant-design/pull/30869) [@crazyair](https://github.com/crazyair)
- 🐞 Fix Typography incorrect ellipsis width when customize `font-size`. [#30840](https://github.com/ant-design/ant-design/pull/30840)
- 🐞 Fix Progress `type="circle"` throws error `Rendered more hooks than during the previous render` sometimes. [#30855](https://github.com/ant-design/ant-design/pull/30855)
- 💄 Optimize Tooltip content width. [#30822](https://github.com/ant-design/ant-design/pull/30822) [@donysukardi](https://github.com/donysukardi)
- Table
- 🛠 Optimize state display logic of select all checkbox in Table. [#30811](https://github.com/ant-design/ant-design/pull/30811) [@kerm1it](https://github.com/kerm1it)
- 🐞 Fix Table column which contains filters or sorters cannot work with `onClick` and `ellipsis` property. [#30799](https://github.com/ant-design/ant-design/pull/30799)
- 💄 Fix Dropdown Item with link color style and click icon can also trigger link effect now. [#30802](https://github.com/ant-design/ant-design/pull/30802)
- 💄 Remove duplicated css reset styles for render performance. [#30660](https://github.com/ant-design/ant-design/pull/30660) [@renzhao1113](https://github.com/renzhao1113)
- TypeScript
- 🤖 Adjust Form, Input, Locale, PageHeader component definition. [#30776](https://github.com/ant-design/ant-design/pull/30776) [@qqabcv520](https://github.com/qqabcv520)
## 4.16.1
`2021-05-30`

18
CHANGELOG.zh-CN.md

@ -15,6 +15,24 @@ timeline: true
---
## 4.16.2
`2021-06-07`
- 🐞 修复 Menu `horizontal` 模式下的自动省略布局会被 `float` 破坏的问题。[#30879](https://github.com/ant-design/ant-design/pull/30879)
- Typography
- 🐞 修复 Typography.Paragraph 的 `copyable` 会将 React.Fragment 当做数组处理的问题。[#30869](https://github.com/ant-design/ant-design/pull/30869) [@crazyair](https://github.com/crazyair)
- 🐞 修复 Typography 自定义 `font-size` 时省略宽度不正确的问题。[#30840](https://github.com/ant-design/ant-design/pull/30840)
- 🐞 修复 Progress `type="circle"` 有时会报错 `Rendered more hooks than during the previous render` 的问题。[#30855](https://github.com/ant-design/ant-design/pull/30855)
- 💄 优化 Tooltip 内容的宽度。[#30822](https://github.com/ant-design/ant-design/pull/30822) [@donysukardi](https://github.com/donysukardi)
- Table
- 🛠 优化 Table 中全选复选框的状态显示逻辑。[#30811](https://github.com/ant-design/ant-design/pull/30811) [@kerm1it](https://github.com/kerm1it)
- 🐞 修复 Table 列筛选和排序时 `column.title` 设置 `onClick``ellipsis` 无效的问题。[#30799](https://github.com/ant-design/ant-design/pull/30799)
- 💄 修复 Dropdown 条目包含超链接时的颜色样式,另外现在点击图标也能触发超链接效果。[#30802](https://github.com/ant-design/ant-design/pull/30802)
- 💄 移除重复的通配符 reset 样式以优化样式渲染性能。[#30660](https://github.com/ant-design/ant-design/pull/30660) [@renzhao1113](https://github.com/renzhao1113)
- TypeScript
- 🤖 调整 Form, Input, Locale, PageHeader 组件类型定义使其更精确。[#30776](https://github.com/ant-design/ant-design/pull/30776) [@qqabcv520](https://github.com/qqabcv520)
## 4.16.1
`2021-05-30`

86
components/dropdown/style/index.less

@ -32,7 +32,7 @@
}
.@{iconfont-css-prefix}-down::before {
transition: transform 0.2s;
transition: transform @animation-duration-base;
}
}
@ -133,7 +133,7 @@
&-item-group-title {
padding: 5px @control-padding-horizontal;
color: @text-color-secondary;
transition: all 0.3s;
transition: all @animation-duration-slow;
}
&-submenu-popup {
@ -154,6 +154,40 @@
}
}
// ======================= Item Content =======================
&-item {
position: relative;
display: flex;
align-items: center;
}
&-item-icon {
min-width: 12px;
margin-right: 8px;
font-size: @font-size-sm;
}
&-title-content {
> a {
color: inherit;
transition: all @animation-duration-slow;
&:hover {
color: inherit;
}
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
content: '';
}
}
}
// =========================== Item ===========================
&-item,
&-submenu-title {
clear: both;
@ -165,35 +199,7 @@
line-height: @dropdown-line-height;
white-space: nowrap;
cursor: pointer;
transition: all 0.3s;
> .@{iconfont-css-prefix}:first-child,
> a > .@{iconfont-css-prefix}:first-child,
> span > .@{iconfont-css-prefix}:first-child {
min-width: 12px;
margin-right: 8px;
font-size: @font-size-sm;
vertical-align: -0.1em;
}
> a {
display: block;
margin: -5px -@control-padding-horizontal;
padding: 5px @control-padding-horizontal;
color: @text-color;
transition: all 0.3s;
&:hover {
color: @text-color;
}
}
> .@{iconfont-css-prefix} + span > a {
color: @text-color;
transition: all 0.3s;
&:hover {
color: @text-color;
}
}
transition: all @animation-duration-slow;
&:first-child {
& when (@dropdown-edge-child-vertical-padding = 0) {
@ -207,8 +213,7 @@
}
}
&-selected,
&-selected > a {
&-selected {
color: @dropdown-selected-color;
background-color: @item-active-bg;
}
@ -227,21 +232,8 @@
cursor: not-allowed;
}
> .@{iconfont-css-prefix} + span > a,
> a {
position: relative;
color: @disabled-color;
a {
pointer-events: none;
&::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: not-allowed;
content: '';
}
}
}

2
components/empty/index.en-US.md

@ -40,7 +40,7 @@ Empty state placeholder.
<style>
.site-empty-buildIn-img {
background-repeat: no-repeat;
background-size: cover;
background-size: contain;
}
.site-empty-buildIn-simple {
width: 55px;

2
components/empty/index.zh-CN.md

@ -41,7 +41,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/MNbKfLBVb/Empty.svg
<style>
.site-empty-buildIn-img {
background-repeat: no-repeat;
background-size: cover;
background-size: contain;
}
.site-empty-buildIn-simple {
width: 55px;

2
components/form/Form.tsx

@ -31,7 +31,7 @@ export interface FormProps<Values = any> extends Omit<RcFormProps<Values>, 'form
hideRequiredMark?: boolean;
}
const InternalForm: React.ForwardRefRenderFunction<unknown, FormProps> = (props, ref) => {
const InternalForm: React.ForwardRefRenderFunction<FormInstance, FormProps> = (props, ref) => {
const contextSize = React.useContext(SizeContext);
const { getPrefixCls, direction, form: contextForm } = React.useContext(ConfigContext);

6
components/form/hooks/useForm.ts

@ -27,7 +27,7 @@ export default function useForm<Values = any>(form?: FormInstance<Values>): [For
const wrapForm: FormInstance<Values> = React.useMemo(
() =>
form || {
form ?? {
...rcForm,
__INTERNAL__: {
itemRef: (name: InternalNamePath) => (node: React.ReactElement) => {
@ -39,7 +39,7 @@ export default function useForm<Values = any>(form?: FormInstance<Values>): [For
}
},
},
scrollToField: (name: string, options: ScrollOptions = {}) => {
scrollToField: (name: NamePath, options: ScrollOptions = {}) => {
const namePath = toArray(name);
const fieldId = getFieldId(namePath, wrapForm.__INTERNAL__.name);
const node: HTMLElement | null = fieldId ? document.getElementById(fieldId) : null;
@ -52,7 +52,7 @@ export default function useForm<Values = any>(form?: FormInstance<Values>): [For
});
}
},
getFieldInstance: (name: string) => {
getFieldInstance: (name: NamePath) => {
const namePathStr = toNamePathStr(name);
return itemsRef.current[namePathStr];
},

18
components/input/Input.tsx

@ -61,15 +61,15 @@ export function fixControlledValue<T>(value: T) {
return value;
}
export function resolveOnChange(
target: HTMLInputElement | HTMLTextAreaElement,
export function resolveOnChange<E extends HTMLInputElement | HTMLTextAreaElement>(
target: E,
e:
| React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
| React.ChangeEvent<E>
| React.MouseEvent<HTMLElement, MouseEvent>
| React.CompositionEvent<HTMLElement>,
onChange:
| undefined
| ((event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void),
| ((event: React.ChangeEvent<E>) => void),
targetValue?: string,
) {
if (!onChange) {
@ -85,7 +85,7 @@ export function resolveOnChange(
event.currentTarget = target;
// change target ref value cause e.target.value should be '' when clear input
target.value = '';
onChange(event as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>);
onChange(event as React.ChangeEvent<E>);
// reset target ref value
target.value = originalInputValue;
return;
@ -98,10 +98,10 @@ export function resolveOnChange(
event.currentTarget = target;
target.value = targetValue;
onChange(event as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>);
onChange(event as React.ChangeEvent<E>);
return;
}
onChange(event as React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>);
onChange(event as React.ChangeEvent<E>);
}
export function getInputClassName(
@ -168,9 +168,9 @@ class Input extends React.Component<InputProps, InputState> {
type: 'text',
};
input: HTMLInputElement;
input!: HTMLInputElement;
clearableInput: ClearableLabeledInput;
clearableInput!: ClearableLabeledInput;
removePasswordTimeout: any;

144
components/layout/__tests__/__snapshots__/demo.test.js.snap

@ -1351,6 +1351,150 @@ exports[`renders ./components/layout/demo/top.md correctly 1`] = `
nav 3
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:3"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 4
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:4"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 5
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:5"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 6
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:6"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 7
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:7"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 8
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:8"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 9
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:9"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 10
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:10"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 11
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:11"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 12
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:12"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 13
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:13"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 14
</span>
</li>
<li
class="ant-menu-overflow-item ant-menu-item ant-menu-item-only-child"
role="menuitem"
style="opacity:1;order:14"
tabindex="-1"
>
<span
class="ant-menu-title-content"
>
nav 15
</span>
</li>
<li
aria-hidden="true"
class="ant-menu-overflow-item ant-menu-overflow-item-rest ant-menu-submenu ant-menu-submenu-horizontal"

7
components/layout/demo/top.md

@ -29,9 +29,10 @@ ReactDOM.render(
<Header>
<div className="logo" />
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
<Menu.Item key="1">nav 1</Menu.Item>
<Menu.Item key="2">nav 2</Menu.Item>
<Menu.Item key="3">nav 3</Menu.Item>
{new Array(15).fill(null).map((_, index) => {
const key = index + 1;
return <Menu.Item key={key}>{`nav ${key}`}</Menu.Item>;
})}
</Menu>
</Header>
<Content style={{ padding: '0 50px' }}>

25
components/locale-provider/LocaleReceiver.tsx

@ -3,35 +3,28 @@ import defaultLocaleData from './default';
import LocaleContext from './context';
import { Locale } from '.';
export interface LocaleReceiverProps {
componentName?: string;
defaultLocale?: object | Function;
children: (locale: object, localeCode?: string, fullLocale?: object) => React.ReactNode;
export interface LocaleReceiverProps<C extends keyof Locale = keyof Locale> {
componentName: C;
defaultLocale?: Locale[C] | (() => Locale[C]);
children: (locale: Exclude<Locale[C], undefined>, localeCode?: string, fullLocale?: object) => React.ReactNode;
}
interface LocaleInterface {
[key: string]: any;
}
export interface LocaleReceiverContext {
antLocale?: LocaleInterface;
}
export default class LocaleReceiver extends React.Component<LocaleReceiverProps> {
export default class LocaleReceiver<C extends keyof Locale = keyof Locale> extends React.Component<LocaleReceiverProps<C>> {
static defaultProps = {
componentName: 'global',
};
static contextType = LocaleContext;
getLocale() {
getLocale(): Exclude<Locale[C], undefined> {
const { componentName, defaultLocale } = this.props;
const locale: object | Function =
defaultLocale || (defaultLocaleData as LocaleInterface)[componentName || 'global'];
const locale =
defaultLocale || defaultLocaleData[componentName ?? 'global'];
const antLocale = this.context;
const localeFromContext = componentName && antLocale ? antLocale[componentName] : {};
return {
...(typeof locale === 'function' ? locale() : locale),
...(locale instanceof Function ? locale() : locale),
...(localeFromContext || {}),
};
}

14
components/locale-provider/index.tsx

@ -18,19 +18,19 @@ export interface Locale {
locale: string;
Pagination?: PaginationLocale;
DatePicker?: DatePickerLocale;
TimePicker?: Object;
Calendar?: Object;
TimePicker?: Record<string, any>;
Calendar?: Record<string, any>;
Table?: TableLocale;
Modal?: ModalLocale;
Popconfirm?: PopconfirmLocale;
Transfer?: Partial<TransferLocale>;
Select?: Object;
Select?: Record<string, any>;
Upload?: UploadLocale;
Empty?: TransferLocaleForEmpty;
global?: Object;
PageHeader?: Object;
Icon?: Object;
Text?: Object;
global?: Record<string, any>;
PageHeader?: { back: string };
Icon?: Record<string, any>;
Text?: Record<string, any>;
Form?: {
optional?: string;
defaultValidateMessages: ValidateMessages;

9
components/menu/style/index.less

@ -40,6 +40,15 @@
list-style: none;
}
// Overflow ellipsis
&-overflow {
display: flex;
&-item {
flex: none;
}
}
&-hidden,
&-submenu-hidden {
display: none;

6
components/page-header/index.tsx

@ -22,7 +22,7 @@ export interface PageHeaderProps {
footer?: React.ReactNode;
extra?: React.ReactNode;
avatar?: AvatarProps;
onBack?: (e: React.MouseEvent<HTMLDivElement>) => void;
onBack?: (e?: React.MouseEvent<HTMLDivElement>) => void;
className?: string;
ghost?: boolean;
}
@ -30,7 +30,7 @@ export interface PageHeaderProps {
const renderBack = (
prefixCls: string,
backIcon?: React.ReactNode,
onBack?: (e: React.MouseEvent<HTMLElement>) => void,
onBack?: (e?: React.MouseEvent<HTMLDivElement>) => void,
) => {
if (!backIcon || !onBack) {
return null;
@ -40,7 +40,7 @@ const renderBack = (
{({ back }: { back: string }) => (
<div className={`${prefixCls}-back`}>
<TransButton
onClick={(e: React.MouseEvent<HTMLDivElement>) => {
onClick={(e?: React.MouseEvent<HTMLDivElement>) => {
onBack?.(e);
}}
className={`${prefixCls}-back-button`}

24
components/progress/Circle.tsx

@ -12,24 +12,8 @@ interface CircleProps extends ProgressProps {
}
function getPercentage({ percent, success, successPercent }: CircleProps) {
const ptg = validProgress(percent);
const realSuccessPercent = getSuccessPercent({ success, successPercent });
if (!realSuccessPercent) {
return ptg;
}
return [
validProgress(realSuccessPercent),
validProgress(ptg - validProgress(realSuccessPercent)),
];
}
function getStrokeColor({ success, strokeColor, successPercent }: CircleProps) {
const color = strokeColor || null;
const realSuccessPercent = getSuccessPercent({ success, successPercent });
if (!realSuccessPercent) {
return color;
}
return [presetPrimaryColors.green, color];
const realSuccessPercent = validProgress(getSuccessPercent({ success, successPercent }));
return [realSuccessPercent, validProgress(validProgress(percent) - realSuccessPercent)];
}
const Circle: React.FC<CircleProps> = props => {
@ -65,8 +49,8 @@ const Circle: React.FC<CircleProps> = props => {
};
// using className to style stroke color
const strokeColor = getStrokeColor(props) as string | string[] | object;
const isGradient = Object.prototype.toString.call(strokeColor) === '[object Object]';
const isGradient = Object.prototype.toString.call(props.strokeColor) === '[object Object]';
const strokeColor = [presetPrimaryColors.green, props.strokeColor || null];
const wrapperClassName = classNames(`${prefixCls}-inner`, {
[`${prefixCls}-circle-gradient`]: isGradient,

180
components/progress/__tests__/__snapshots__/demo.test.js.snap

@ -35,6 +35,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:221.48228207808043px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -77,6 +89,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:206.7167966062084px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -136,6 +160,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:295.3097094374406px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -200,6 +236,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -303,6 +351,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:88.59291283123217px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -345,6 +405,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:206.7167966062084px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -404,6 +476,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:295.3097094374406px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -468,6 +552,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:165.23228207808043px 295.3097094374406px;stroke-dashoffset:-37.5px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,47
a 47,47 0 1 1 0,-94
a 47,47 0 1 1 0,94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-37.5px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -510,6 +606,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:198.98228207808043px 295.3097094374406px;stroke-dashoffset:-15px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,47
a 47,47 0 1 1 0,-94
a 47,47 0 1 1 0,94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-15px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -640,6 +748,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:221.48228207808043px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -682,6 +802,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:295.3097094374406px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -791,6 +923,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:265.77873849369655px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -851,6 +995,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:295.3097094374406px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -1209,6 +1365,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:221.48228207808043px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="square"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -1251,6 +1419,18 @@ Array [
stroke-width="6"
style="stroke-dasharray:165.23228207808043px 295.3097094374406px;stroke-dashoffset:-37.5px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,47
a 47,47 0 1 1 0,-94
a 47,47 0 1 1 0,94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="square"
stroke-width="6"
style="stroke:#52C41A;stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-37.5px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"

48
components/progress/__tests__/__snapshots__/index.test.js.snap

@ -34,6 +34,18 @@ exports[`Progress render dashboard 295 gapDegree 1`] = `
stroke-width="6"
style="stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -147.5px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,47
a 47,47 0 1 1 0,-94
a 47,47 0 1 1 0,94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke: #52C41A; stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -147.5px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
</svg>
<span
class="ant-progress-text"
@ -79,6 +91,18 @@ exports[`Progress render dashboard 296 gapDegree 1`] = `
stroke-width="6"
style="stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -148px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,47
a 47,47 0 1 1 0,-94
a 47,47 0 1 1 0,94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke: #52C41A; stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -148px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
</svg>
<span
class="ant-progress-text"
@ -124,6 +148,18 @@ exports[`Progress render dashboard zero gapDegree 1`] = `
stroke-width="6"
style="stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,47
a 47,47 0 1 1 0,-94
a 47,47 0 1 1 0,94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke: #52C41A; stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
</svg>
<span
class="ant-progress-text"
@ -361,6 +397,18 @@ exports[`Progress render strokeColor 1`] = `
stroke-width="6"
style="stroke: red; stroke-dasharray: 147.6548547187203px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="6"
style="stroke: #52C41A; stroke-dasharray: 0px 295.3097094374406px; stroke-dashoffset: -0px; transition: stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s; transition-duration: .3s, .3s, .3s, .06s;"
/>
</svg>
<span
class="ant-progress-text"

10
components/progress/__tests__/index.test.js

@ -204,4 +204,14 @@ describe('Progress', () => {
'Warning: [antd: Progress] `success.progress` is deprecated. Please use `success.percent` instead.',
);
});
// https://github.com/ant-design/ant-design/issues/30685
describe('github issues', () => {
it('"Rendered more hooks than during the previous render"', () => {
expect(() => {
const wrapper = mount(<Progress percent={60} success={{ percent: 0 }} type="circle" />);
wrapper.setProps({ success: { percent: 10 } });
}).not.toThrow();
});
});
});

5
components/progress/progress.tsx

@ -83,8 +83,9 @@ export default class Progress extends React.Component<ProgressProps> {
renderProcessInfo(prefixCls: string, progressStatus: typeof ProgressStatuses[number]) {
const { showInfo, format, type, percent } = this.props;
const successPercent = getSuccessPercent(this.props);
if (!showInfo) return null;
if (!showInfo) {
return null;
}
let text;
const textFormatter = format || (percentNumber => `${percentNumber}%`);
const isLineType = type === 'line';

60
components/steps/__tests__/__snapshots__/demo.test.js.snap

@ -1289,6 +1289,18 @@ exports[`renders ./components/steps/demo/progress.md correctly 1`] = `
stroke-width="4"
style="stroke-dasharray:180.95573684677208px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-48
a 48,48 0 1 1 0,96
a 48,48 0 1 1 0,-96"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -1522,6 +1534,18 @@ Array [
stroke-width="4"
style="stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-48
a 48,48 0 1 1 0,96
a 48,48 0 1 1 0,-96"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -1695,6 +1719,18 @@ Array [
stroke-width="4"
style="stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-48
a 48,48 0 1 1 0,96
a 48,48 0 1 1 0,-96"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -1868,6 +1904,18 @@ Array [
stroke-width="4"
style="stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-48
a 48,48 0 1 1 0,96
a 48,48 0 1 1 0,-96"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"
@ -2041,6 +2089,18 @@ Array [
stroke-width="4"
style="stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-48
a 48,48 0 1 1 0,96
a 48,48 0 1 1 0,-96"
fill-opacity="0"
opacity="0"
stroke=""
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:0px 301.59289474462014px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s"
/>
</svg>
<span
class="ant-progress-text"

68
components/table/__tests__/Table.rowSelection.test.js

@ -865,6 +865,74 @@ describe('Table.rowSelection', () => {
expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeFalsy();
});
it('should make select all checked when each item is checked and disabled', () => {
const wrapper = mount(
createTable({
rowSelection: {
selectedRowKeys: [0, 1, 2, 3],
getCheckboxProps: () => ({
disabled: true,
}),
},
}),
);
expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeTruthy();
expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeTruthy();
});
it('should make select all indeterminated when each item is disabled and some item is checked', () => {
const wrapper = mount(
createTable({
rowSelection: {
selectedRowKeys: [0],
getCheckboxProps: () => ({
disabled: true,
}),
},
}),
);
expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeTruthy();
expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeFalsy();
expect(
wrapper.find('thead .ant-checkbox-indeterminate.ant-checkbox-disabled').exists(),
).toBeTruthy();
});
it('should make select all checked when each item is checked and some item is disabled', () => {
const wrapper = mount(
createTable({
rowSelection: {
selectedRowKeys: [0, 1, 2, 3],
getCheckboxProps: record => ({
disabled: record.key === 0,
}),
},
}),
);
expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeFalsy();
expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeTruthy();
});
it('should not make select all checked when some item is checked and disabled', () => {
const wrapper = mount(
createTable({
rowSelection: {
selectedRowKeys: [1],
getCheckboxProps: record => ({
disabled: record.key === 0,
}),
},
}),
);
expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeFalsy();
expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeFalsy();
expect(wrapper.find('thead .ant-checkbox-indeterminate').exists()).toBeTruthy();
});
it('should onRowClick not called when checkbox clicked', () => {
const onRowClick = jest.fn();

40
components/table/hooks/useSelection.tsx

@ -124,7 +124,7 @@ export default function useSelection<RecordType>(
() =>
checkStrictly
? { keyEntities: null }
: convertDataToEntities((data as unknown) as DataNode[], {
: convertDataToEntities(data as unknown as DataNode[], {
externalGetKey: getRowKey as any,
childrenPropName: childrenColumnName,
}),
@ -132,10 +132,10 @@ export default function useSelection<RecordType>(
);
// Get flatten data
const flattedData = useMemo(() => flattenData(pageData, childrenColumnName), [
pageData,
childrenColumnName,
]);
const flattedData = useMemo(
() => flattenData(pageData, childrenColumnName),
[pageData, childrenColumnName],
);
// Get all checkbox props
const checkboxPropsMap = useMemo(() => {
@ -395,17 +395,33 @@ export default function useSelection<RecordType>(
);
}
const allDisabled = flattedData.every((record, index) => {
const key = getRowKey(record, index);
const checkboxProps = checkboxPropsMap.get(key) || {};
return checkboxProps.disabled;
});
const allDisabledData = flattedData
.map((record, index) => {
const key = getRowKey(record, index);
const checkboxProps = checkboxPropsMap.get(key) || {};
return { checked: keySet.has(key), ...checkboxProps };
})
.filter(({ disabled }) => disabled);
const allDisabled =
!!allDisabledData.length && allDisabledData.length === flattedData.length;
const allDisabledAndChecked =
allDisabled && allDisabledData.every(({ checked }) => checked);
const allDisabledSomeChecked =
allDisabled && allDisabledData.some(({ checked }) => checked);
title = !hideSelectAll && (
<div className={`${prefixCls}-selection`}>
<Checkbox
checked={!allDisabled && !!flattedData.length && checkedCurrentAll}
indeterminate={!checkedCurrentAll && checkedCurrentSome}
checked={
!allDisabled ? !!flattedData.length && checkedCurrentAll : allDisabledAndChecked
}
indeterminate={
!allDisabled
? !checkedCurrentAll && checkedCurrentSome
: !allDisabledAndChecked && allDisabledSomeChecked
}
onChange={onSelectAllChange}
disabled={flattedData.length === 0 || allDisabled}
skipGroup

8
components/table/style/index.less

@ -60,6 +60,12 @@
text-overflow: ellipsis;
}
}
.@{table-prefix-cls}-column-title {
overflow: hidden;
text-overflow: ellipsis;
word-break: keep-all;
}
}
// ============================ Title =============================
@ -232,6 +238,8 @@
}
&-column-title {
position: relative;
z-index: 1;
flex: 1;
}

1
components/tooltip/style/index.less

@ -18,6 +18,7 @@
position: absolute;
z-index: @zindex-tooltip;
display: block;
width: max-content;
max-width: @tooltip-max-width;
visibility: visible;

31
components/typography/Base.tsx

@ -93,6 +93,13 @@ function wrapperDecorations(
return currentContent;
}
function getNode(dom: React.ReactNode, defaultNode: React.ReactNode, needDom?: boolean) {
if (dom === true || dom === undefined) {
return defaultNode;
}
return dom || (needDom && defaultNode);
}
interface InternalBlockProps extends BlockProps {
component: string;
}
@ -391,23 +398,27 @@ class Base extends React.Component<InternalBlockProps, BaseState> {
const prefixCls = this.getPrefixCls();
const { tooltips } = copyable as CopyConfig;
let tooltipNodes = toArray(tooltips) as React.ReactNode[];
if (tooltipNodes.length === 0) {
tooltipNodes = [this.copyStr, this.copiedStr];
}
const title = copied ? tooltipNodes[1] : tooltipNodes[0];
const ariaLabel = typeof title === 'string' ? title : '';
const icons = toArray((copyable as CopyConfig).icon);
const { tooltips, icon } = copyable as CopyConfig;
const tooltipNodes = Array.isArray(tooltips) ? tooltips : [tooltips];
const iconNodes = Array.isArray(icon) ? icon : [icon];
const title = copied
? getNode(tooltipNodes[1], this.copiedStr)
: getNode(tooltipNodes[0], this.copyStr);
const systemStr = copied ? this.copiedStr : this.copyStr;
const ariaLabel = typeof title === 'string' ? title : systemStr;
return (
<Tooltip key="copy" title={tooltips === false ? '' : title}>
<Tooltip key="copy" title={title}>
<TransButton
className={classNames(`${prefixCls}-copy`, copied && `${prefixCls}-copy-success`)}
onClick={this.onCopyClick}
aria-label={ariaLabel}
>
{copied ? icons[1] || <CheckOutlined /> : icons[0] || <CopyOutlined />}
{copied
? getNode(iconNodes[1], <CheckOutlined />, true)
: getNode(iconNodes[0], <CopyOutlined />, true)}
</TransButton>
</Tooltip>
);

197
components/typography/__tests__/copy.test.tsx

@ -0,0 +1,197 @@
import React from 'react';
import { mount } from 'enzyme';
import { SmileOutlined, LikeOutlined } from '@ant-design/icons';
import Base from '../Base';
describe('Typography copy', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
afterEach(() => {
errorSpy.mockReset();
});
describe('Base', () => {
describe('copyable', () => {
function copyTest({
name,
icon,
tooltips,
iconClassNames = [],
iconTexts = [],
tooltipTexts = [],
tooltipLength,
}: {
name: string;
icon?: boolean | React.ReactNode;
tooltips?: boolean | React.ReactNode;
iconClassNames?: string[];
iconTexts?: string[];
tooltipTexts?: string[];
tooltipLength?: number;
}) {
it(name, async () => {
jest.useFakeTimers();
const wrapper = mount(
<Base component="p" copyable={{ icon, tooltips }}>
test copy
</Base>,
);
if (iconClassNames[0] !== undefined) {
expect(wrapper.exists(iconClassNames[0])).toBeTruthy();
}
if (iconTexts[0] !== undefined) {
expect(wrapper.find('.ant-typography-copy').at(0).text()).toBe(iconTexts[0]);
}
wrapper.find('.ant-typography-copy').first().simulate('mouseenter');
jest.runAllTimers();
wrapper.update();
if (tooltipTexts[0] !== undefined) {
expect(wrapper.find('.ant-tooltip-inner').text()).toBe(tooltipTexts[0]);
}
if (tooltipLength !== undefined) {
expect(wrapper.find('.ant-tooltip-inner').length).toBe(tooltipLength);
}
wrapper.find('.ant-typography-copy').first().simulate('click');
jest.useRealTimers();
if (iconClassNames[1] !== undefined) {
expect(wrapper.exists(iconClassNames[1])).toBeTruthy();
}
wrapper.find('.ant-typography-copy').first().simulate('mouseenter');
wrapper.update();
wrapper.find('.ant-typography-copy').first().simulate('mouseenter');
if (tooltipTexts[1] !== undefined) {
expect(wrapper.find('.ant-tooltip-inner').text()).toBe(tooltipTexts[1]);
}
if (iconTexts[1] !== undefined) {
expect(wrapper.find('.ant-typography-copy').at(0).text()).toBe(iconTexts[1]);
}
jest.useFakeTimers();
wrapper.find('.ant-typography-copy').first().simulate('click');
jest.runAllTimers();
wrapper.update();
wrapper.unmount();
jest.useRealTimers();
});
}
const dom = (
<>
<span>1</span>2
</>
);
const dom2 = (
<>
<span>3</span>4
</>
);
const copy = '.anticon-copy';
const check = '.anticon-check';
copyTest({
name: 'icon basic copy',
iconClassNames: [copy, check],
tooltipTexts: ['Copy', 'Copied'],
});
copyTest({ name: 'icon true', icon: true, iconClassNames: [copy, check] });
copyTest({ name: 'icon two true', icon: [true, true], iconClassNames: [copy, check] });
copyTest({ name: 'icon false', icon: false, iconClassNames: [copy, check] });
copyTest({ name: 'icon custom text', icon: ['a', 'b'], iconTexts: ['a', 'b'] });
copyTest({ name: 'icon custom element', icon: [dom, dom2], iconTexts: ['12', '34'] });
copyTest({
name: 'icon custom icon',
icon: <SmileOutlined />,
iconClassNames: ['.anticon-smile', check],
});
copyTest({
name: 'icon custom icon2',
icon: [<SmileOutlined key="a" />, <LikeOutlined key="b" />],
iconClassNames: ['.anticon-smile', '.anticon-like'],
});
copyTest({
name: 'icon custom icon3',
icon: [
<>
<SmileOutlined />
<SmileOutlined />
</>,
<LikeOutlined key="b" />,
],
iconClassNames: ['.anticon-smile', '.anticon-like'],
});
copyTest({
name: 'icon custom icon4',
icon: (
<>
<SmileOutlined />
<LikeOutlined />
</>
),
iconClassNames: ['.anticon-smile', check],
});
copyTest({
name: 'icon custom icon5',
icon: (
<>
<SmileOutlined />
<LikeOutlined />
</>
),
iconClassNames: ['.anticon-like', check],
});
copyTest({
name: 'tooltips true',
tooltips: true,
tooltipLength: 1,
tooltipTexts: ['Copy', 'Copied'],
});
copyTest({ name: 'tooltips false', tooltips: false, tooltipLength: 0 });
copyTest({
name: 'tooltips custom text',
tooltips: ['a', 'b'],
tooltipLength: 1,
tooltipTexts: ['a', 'b'],
});
copyTest({
name: 'tooltips custom element ',
tooltips: [dom, dom2],
tooltipTexts: ['12', '34'],
});
copyTest({
name: 'tooltips first empty',
tooltips: ['', 'xxx'],
tooltipLength: 0,
});
copyTest({
name: 'tooltips first empty 2',
tooltips: [''],
tooltipLength: 0,
});
copyTest({
name: 'tooltips true true',
tooltips: [true, true],
tooltipTexts: ['Copy', 'Copied'],
});
copyTest({
name: 'tooltips true false',
tooltips: [true, false],
tooltipTexts: ['Copy', ''],
});
copyTest({
name: 'tooltips false true',
tooltips: [false, true],
tooltipLength: 0,
});
});
});
});

9
components/typography/util.tsx

@ -77,11 +77,10 @@ export default (
const originStyle = window.getComputedStyle(originEle);
const originCSS = styleToString(originStyle);
const lineHeight = pxToNumber(originStyle.lineHeight);
const maxHeight = Math.round(
lineHeight * (rows + 1) +
pxToNumber(originStyle.paddingTop) +
pxToNumber(originStyle.paddingBottom),
);
const maxHeight =
Math.floor(lineHeight) * (rows + 1) +
pxToNumber(originStyle.paddingTop) +
pxToNumber(originStyle.paddingBottom);
// Set shadow
ellipsisContainer.setAttribute('style', originCSS);

6
docs/react/replace-moment.zh-CN.md

@ -19,7 +19,7 @@ title: 替换 Moment.js
```tsx
import { Dayjs } from 'dayjs';
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
import dayjsGenerateConfig from 'rc-picker/es/generate/dayjs';
import generatePicker from 'antd/es/date-picker/generatePicker';
import 'antd/es/date-picker/style/index';
@ -60,7 +60,7 @@ export default TimePicker;
```tsx
import { Dayjs } from 'dayjs';
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
import dayjsGenerateConfig from 'rc-picker/es/generate/dayjs';
import generateCalendar from 'antd/es/calendar/generateCalendar';
import 'antd/es/calendar/style';
@ -126,7 +126,7 @@ module.exports = {
编写如下代码:
```tsx
import dateFnsGenerateConfig from 'rc-picker/lib/generate/dateFns';
import dateFnsGenerateConfig from 'rc-picker/es/generate/dateFns';
import generatePicker from 'antd/es/date-picker/generatePicker';
import 'antd/es/date-picker/style/index';

6
package.json

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "4.16.1",
"version": "4.16.2",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
"keywords": [
@ -205,7 +205,7 @@
"eslint-plugin-markdown": "^2.0.0",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react-hooks": "^4.1.2",
"eslint-plugin-unicorn": "^32.0.1",
"eslint-plugin-unicorn": "^33.0.0",
"fetch-jsonp": "^1.1.3",
"fs-extra": "^10.0.0",
"full-icu": "^1.3.0",
@ -290,7 +290,7 @@
"bundlesize": [
{
"path": "./dist/antd.min.js",
"maxSize": "275 kB"
"maxSize": "270 kB"
},
{
"path": "./dist/antd.min.css",

25
site/theme/template/Home/RecommendPage.less

@ -1,5 +1,13 @@
@import '../../../../components/style/themes/default.less';
.linear-gradient(@mid-pos, @end-pos) {
background: linear-gradient(
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.25) @mid-pos,
rgba(0, 0, 0, 0.65) @end-pos
);
}
.recommend-block {
position: relative;
display: block;
@ -37,16 +45,15 @@
}
&::before {
.linear-gradient(40%, 100%);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0, 0.25) 30%,
rgba(0, 0, 0, 0.5) 100%
);
opacity: 0.3;
transition: all 0.5s;
content: '';
pointer-events: none;
}
@ -107,9 +114,17 @@
.recommend-block {
&-main {
height: 408px;
&::before {
.linear-gradient(70%, 100%);
}
}
&:hover {
&::before {
opacity: 1;
}
.recommend-content {
transform: translateY(0);

Loading…
Cancel
Save