Merge branch 'master' into resolve-conflict-1

This commit is contained in:
07akioni 2020-07-26 20:14:11 +08:00 committed by GitHub
commit 9951e583b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 823 additions and 360 deletions

View File

@ -5,6 +5,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-banner"
data-show="true"
role="alert"
>
<span
aria-label="exclamation-circle"
@ -39,6 +40,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-banner ant-alert-closable"
data-show="true"
role="alert"
>
<span
aria-label="exclamation-circle"
@ -99,6 +101,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-banner"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -113,6 +116,7 @@ Array [
<div
class="ant-alert ant-alert-error ant-alert-banner"
data-show="true"
role="alert"
>
<span
aria-label="close-circle"
@ -150,6 +154,7 @@ exports[`renders ./components/alert/demo/basic.md correctly 1`] = `
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -167,6 +172,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-no-icon ant-alert-closable"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -206,6 +212,7 @@ Array [
<div
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon ant-alert-closable"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -251,6 +258,7 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = `
<div
class="ant-alert ant-alert-info ant-alert-no-icon ant-alert-closable"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -279,6 +287,7 @@ Array [
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -292,6 +301,7 @@ Array [
<div
class="ant-alert ant-alert-success"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -325,6 +335,7 @@ Array [
<div
class="ant-alert ant-alert-info"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -358,6 +369,7 @@ Array [
<div
class="ant-alert ant-alert-warning"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -391,6 +403,7 @@ Array [
<div
class="ant-alert ant-alert-error"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -424,6 +437,7 @@ Array [
<div
class="ant-alert ant-alert-success ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -459,6 +473,7 @@ Array [
<div
class="ant-alert ant-alert-info ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -494,6 +509,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -529,6 +545,7 @@ Array [
<div
class="ant-alert ant-alert-error ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="smile"
@ -569,6 +586,7 @@ Array [
<div
class="ant-alert ant-alert-success ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -584,6 +602,7 @@ Array [
<div
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -599,6 +618,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -614,6 +634,7 @@ Array [
<div
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -645,6 +666,7 @@ Array [
<div
class="ant-alert ant-alert-success"
data-show="true"
role="alert"
>
<span
aria-label="check-circle"
@ -678,6 +700,7 @@ Array [
<div
class="ant-alert ant-alert-info"
data-show="true"
role="alert"
>
<span
aria-label="info-circle"
@ -711,6 +734,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-closable"
data-show="true"
role="alert"
>
<span
aria-label="exclamation-circle"
@ -770,6 +794,7 @@ Array [
<div
class="ant-alert ant-alert-error"
data-show="true"
role="alert"
>
<span
aria-label="close-circle"
@ -803,6 +828,7 @@ Array [
<div
class="ant-alert ant-alert-success ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="check-circle"
@ -841,6 +867,7 @@ Array [
<div
class="ant-alert ant-alert-info ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="info-circle"
@ -879,6 +906,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-with-description ant-alert-closable"
data-show="true"
role="alert"
>
<span
aria-label="exclamation-circle"
@ -943,6 +971,7 @@ Array [
<div
class="ant-alert ant-alert-error ant-alert-with-description"
data-show="true"
role="alert"
>
<span
aria-label="close-circle"
@ -985,6 +1014,7 @@ exports[`renders ./components/alert/demo/loop-banner.md correctly 1`] = `
<div
class="ant-alert ant-alert-warning ant-alert-banner"
data-show="true"
role="alert"
>
<span
aria-label="exclamation-circle"
@ -1037,6 +1067,7 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = `
<div
class="ant-alert ant-alert-success ant-alert-no-icon ant-alert-closable"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -1084,6 +1115,7 @@ Array [
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -1097,6 +1129,7 @@ Array [
<div
class="ant-alert ant-alert-info ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -1110,6 +1143,7 @@ Array [
<div
class="ant-alert ant-alert-warning ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -1123,6 +1157,7 @@ Array [
<div
class="ant-alert ant-alert-error ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"

View File

@ -4,6 +4,7 @@ exports[`Alert ErrorBoundary 1`] = `
<div
class="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -26,6 +27,7 @@ exports[`Alert could accept none react element icon 1`] = `
<div
class="ant-alert ant-alert-success"
data-show="true"
role="alert"
>
<span
class="ant-alert-icon"
@ -47,6 +49,7 @@ exports[`Alert rtl render component should be rendered correctly in RTL directio
<div
class="ant-alert ant-alert-info ant-alert-no-icon ant-alert-rtl"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"

View File

@ -176,6 +176,7 @@ const Alert: AlertInterface = ({
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onClick={onClick}
role="alert"
{...dataOrAriaProps}
>
{isShowIcon ? renderIconNode() : null}

View File

@ -158,4 +158,23 @@ describe('Avatar Render', () => {
wrapper.simulate('mouseenter');
expect(onMouseEnter).toHaveBeenCalled();
});
it('fallback', () => {
const div = global.document.createElement('div');
global.document.body.appendChild(div);
const wrapper = mount(
<Avatar
shape="circle"
src="http://error.url"
>
A
</Avatar>,
{ attachTo: div },
);
wrapper.find('img').simulate('error');
wrapper.update();
expect(wrapper).toMatchRenderedSnapshot();
wrapper.detach();
global.document.body.removeChild(div);
});
});

View File

@ -1,5 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Avatar Render fallback 1`] = `
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="http://error.url"
/>
</span>
`;
exports[`Avatar Render rtl render component should be rendered correctly in RTL direction 1`] = `
<span
class="ant-avatar ant-avatar-circle"

View File

@ -583,6 +583,25 @@ Array [
]
`;
exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
Array [
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="http://abc.com/not-exist.jpg"
/>
</span>,
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="http://abc.com/not-exist.jpg"
/>
</span>,
]
`;
exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
Array [
<button

View File

@ -0,0 +1,37 @@
---
order: 99
title:
zh-CN: 图片不存在时
en-US: Fallback
debug: true
---
## zh-CN
图片不存在时,会回退到 `src`
## en-US
图片不存在时,会回退到 `src`
```tsx
import { Avatar } from 'antd';
ReactDOM.render(
<>
<Avatar
shape="circle"
src="http://abc.com/not-exist.jpg"
>
A
</Avatar>
<Avatar
shape="circle"
src="http://abc.com/not-exist.jpg"
>
ABC
</Avatar>
</>,
mountNode,
);
```

View File

@ -12,5 +12,181 @@ interface CompoundedComponent
const Avatar = InternalAvatar as CompoundedComponent;
Avatar.Group = Group;
const Avatar: React.FC<AvatarProps> = props => {
const [scale, setScale] = React.useState(1);
const [mounted, setMounted] = React.useState(false);
const [isImgExist, setIsImgExist] = React.useState(true);
const avatarNodeRef = React.useRef<HTMLElement>();
const avatarChildrenRef = React.useRef<HTMLElement>();
let lastChildrenWidth: number;
let lastNodeWidth: number;
const { getPrefixCls } = React.useContext(ConfigContext);
const setScaleParam = () => {
if (!avatarChildrenRef.current || !avatarNodeRef.current) {
return;
}
const childrenWidth = avatarChildrenRef.current.offsetWidth; // offsetWidth avoid affecting be transform scale
const nodeWidth = avatarNodeRef.current.offsetWidth;
const { gap = 4 } = props;
// denominator is 0 is no meaning
if (
childrenWidth !== 0 &&
nodeWidth !== 0 &&
(lastChildrenWidth !== childrenWidth || lastNodeWidth !== nodeWidth)
) {
lastChildrenWidth = childrenWidth;
lastNodeWidth = nodeWidth;
}
if (gap * 2 < nodeWidth) {
setScale(nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1);
}
};
React.useEffect(() => {
setMounted(true);
}, []);
React.useEffect(() => {
setIsImgExist(true);
setScale(1);
}, [props.src]);
React.useEffect(() => {
setScaleParam();
}, [props.children, props.gap, props.size]);
React.useEffect(() => {
if (props.children) {
setScaleParam();
}
}, [isImgExist]);
const handleImgLoadError = () => {
const { onError } = props;
const errorFlag = onError ? onError() : undefined;
if (errorFlag !== false) {
setIsImgExist(false);
}
};
const {
prefixCls: customizePrefixCls,
shape,
size,
src,
srcSet,
icon,
className,
alt,
draggable,
children,
...others
} = props;
devWarning(
!(typeof icon === 'string' && icon.length > 2),
'Avatar',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
const sizeCls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
});
const classString = classNames(prefixCls, className, sizeCls, {
[`${prefixCls}-${shape}`]: shape,
[`${prefixCls}-image`]: src && isImgExist,
[`${prefixCls}-icon`]: icon,
});
const sizeStyle: React.CSSProperties =
typeof size === 'number'
? {
width: size,
height: size,
lineHeight: `${size}px`,
fontSize: icon ? size / 2 : 18,
}
: {};
let childrenToRender;
if (src && isImgExist) {
childrenToRender = (
<img src={src} draggable={draggable} srcSet={srcSet} onError={handleImgLoadError} alt={alt} />
);
} else if (icon) {
childrenToRender = icon;
} else if (mounted || scale !== 1) {
const transformString = `scale(${scale}) translateX(-50%)`;
const childrenStyle: React.CSSProperties = {
msTransform: transformString,
WebkitTransform: transformString,
transform: transformString,
};
const sizeChildrenStyle: React.CSSProperties =
typeof size === 'number'
? {
lineHeight: `${size}px`,
}
: {};
childrenToRender = (
<span
className={`${prefixCls}-string`}
ref={(node: HTMLElement) => {
avatarChildrenRef.current = node;
}}
style={{ ...sizeChildrenStyle, ...childrenStyle }}
>
{children}
</span>
);
} else {
childrenToRender = (
<span
className={`${prefixCls}-string`}
style={{ opacity: 0 }}
ref={(node: HTMLElement) => {
avatarChildrenRef.current = node;
}}
>
{children}
</span>
);
}
// The event is triggered twice from bubbling up the DOM tree.
// see https://codesandbox.io/s/kind-snow-9lidz
delete others.onError;
delete others.gap;
return (
<span
{...others}
style={{ ...sizeStyle, ...others.style }}
className={classString}
ref={(node: HTMLElement) => {
avatarNodeRef.current = node;
}}
>
{childrenToRender}
</span>
);
};
Avatar.defaultProps = {
shape: 'circle' as AvatarProps['shape'],
size: 'default' as AvatarProps['size'],
};
export { Group };
export default Avatar;

View File

@ -4203,6 +4203,7 @@ Array [
<div
class="ant-alert ant-alert-info ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"

View File

@ -55,7 +55,7 @@ Fields in `showSearch`:
| --- | --- | --- | --- | --- |
| filter | The function will receive two arguments, inputValue and option, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded | function(inputValue, path): boolean | - | |
| limit | Set the count of filtered items | number \| false | 50 | |
| matchInputWidth | Whether the width of result list equals to input's | boolean | true | |
| matchInputWidth | Whether the width of list matches input, ([how it looks](https://github.com/ant-design/ant-design/issues/25779)) | boolean | true | |
| render | Used to render filtered options | function(inputValue, path): ReactNode | - | |
| sort | Used to sort filtered options | function(a, b, inputValue) | - | |

View File

@ -56,7 +56,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg
| --- | --- | --- | --- | --- |
| filter | 接收 `inputValue` `path` 两个参数,当 `path` 符合筛选条件时,应返回 true反之则返回 false | function(inputValue, path): boolean | - | |
| limit | 搜索结果展示数量 | number \| false | 50 | |
| matchInputWidth | 搜索结果列表是否与输入框同宽 | boolean | true | |
| matchInputWidth | 搜索结果列表是否与输入框同宽[效果](https://github.com/ant-design/ant-design/issues/25779) | boolean | true | |
| render | 用于渲染 filter 后的选项 | function(inputValue, path): ReactNode | - | |
| sort | 用于排序 filter 后的选项 | function(a, b, inputValue) | - | |

View File

@ -4,6 +4,7 @@ exports[`ConfigProvider components Alert configProvider 1`] = `
<div
class="config-alert config-alert-success config-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="config-alert-message"
@ -20,6 +21,7 @@ exports[`ConfigProvider components Alert configProvider componentSize large 1`]
<div
class="config-alert config-alert-success config-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="config-alert-message"
@ -36,6 +38,7 @@ exports[`ConfigProvider components Alert configProvider componentSize middle 1`]
<div
class="config-alert config-alert-success config-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="config-alert-message"
@ -52,6 +55,7 @@ exports[`ConfigProvider components Alert configProvider virtual and dropdownMatc
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -68,6 +72,7 @@ exports[`ConfigProvider components Alert normal 1`] = `
<div
class="ant-alert ant-alert-success ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -84,6 +89,7 @@ exports[`ConfigProvider components Alert prefixCls 1`] = `
<div
class="prefix-Alert prefix-Alert-success prefix-Alert-no-icon"
data-show="true"
role="alert"
>
<span
class="prefix-Alert-message"

View File

@ -0,0 +1,22 @@
import React from 'react';
import { mount } from 'enzyme';
import DatePicker from '..';
import { resetWarned } from '../../_util/devWarning';
const { QuarterPicker } = DatePicker;
describe('QuarterPicker', () => {
it('should support style prop', () => {
resetWarned();
const warnSpy = jest.spyOn(console, 'error');
const wrapper = mount(<QuarterPicker style={{ width: 400 }} />);
expect(wrapper.render()).toMatchSnapshot();
expect(warnSpy).toHaveBeenCalledWith(
"Warning: [antd: QuarterPicker] DatePicker.QuarterPicker is legacy usage. Please use DatePicker[picker='quarter'] directly.",
);
warnSpy.mockRestore();
});
});

View File

@ -0,0 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`QuarterPicker should support style prop 1`] = `
<div
class="ant-picker"
style="width: 400px;"
>
<div
class="ant-picker-input"
>
<input
autocomplete="off"
placeholder="Select quarter"
readonly=""
size="12"
title=""
value=""
/>
<span
class="ant-picker-suffix"
>
<span
aria-label="calendar"
class="anticon anticon-calendar"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="calendar"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
/>
</svg>
</span>
</span>
</div>
</div>
`;

View File

@ -17,14 +17,14 @@ A disabled state of the `DatePicker`. You can also set as array to disable one o
import { DatePicker } from 'antd';
import moment from 'moment';
const { MonthPicker, RangePicker } = DatePicker;
const { RangePicker } = DatePicker;
const dateFormat = 'YYYY-MM-DD';
ReactDOM.render(
<>
<DatePicker defaultValue={moment('2015-06-06', dateFormat)} disabled />
<br />
<MonthPicker defaultValue={moment('2015-06', 'YYYY-MM')} disabled />
<DatePicker picker="month" defaultValue={moment('2015-06', 'YYYY-MM')} disabled />
<br />
<RangePicker
defaultValue={[moment('2015-06-06', dateFormat), moment('2015-06-06', dateFormat)]}

View File

@ -8,6 +8,7 @@ import { PickerMode } from 'rc-picker/lib/interface';
import { GenerateConfig } from 'rc-picker/lib/generate/index';
import enUS from '../locale/en_US';
import { getPlaceholder } from '../util';
import devWarning from '../../_util/devWarning';
import { ConfigContext, ConfigConsumerProps } from '../../config-provider';
import LocaleReceiver from '../../locale-provider/LocaleReceiver';
import SizeContext from '../../config-provider/SizeContext';
@ -36,6 +37,15 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
pickerRef = React.createRef<RCPicker<DateType>>();
constructor(props: InnerPickerProps) {
super(props);
devWarning(
picker !== 'quarter',
displayName!,
`DatePicker.${displayName} is legacy usage. Please use DatePicker[picker='${picker}'] directly.`,
);
}
focus = () => {
if (this.pickerRef.current) {
this.pickerRef.current.focus();
@ -153,6 +163,10 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
const MonthPicker = getPicker<Omit<PickerDateProps<DateType>, 'picker'>>('month', 'MonthPicker');
const YearPicker = getPicker<Omit<PickerDateProps<DateType>, 'picker'>>('year', 'YearPicker');
const TimePicker = getPicker<Omit<PickerTimeProps<DateType>, 'picker'>>('time', 'TimePicker');
const QuarterPicker = getPicker<Omit<PickerTimeProps<DateType>, 'picker'>>(
'quarter',
'QuarterPicker',
);
return { DatePicker, WeekPicker, MonthPicker, YearPicker, TimePicker };
return { DatePicker, WeekPicker, MonthPicker, YearPicker, TimePicker, QuarterPicker };
}

View File

@ -123,9 +123,14 @@ export type RangePickerProps<DateType> =
function generatePicker<DateType>(generateConfig: GenerateConfig<DateType>) {
// =========================== Picker ===========================
const { DatePicker, WeekPicker, MonthPicker, YearPicker, TimePicker } = generateSinglePicker(
generateConfig,
);
const {
DatePicker,
WeekPicker,
MonthPicker,
YearPicker,
TimePicker,
QuarterPicker,
} = generateSinglePicker(generateConfig);
// ======================== Range Picker ========================
const RangePicker = generateRangePicker(generateConfig);
@ -137,6 +142,7 @@ function generatePicker<DateType>(generateConfig: GenerateConfig<DateType>) {
YearPicker: typeof YearPicker;
RangePicker: React.ComponentClass<RangePickerProps<DateType>>;
TimePicker: typeof TimePicker;
QuarterPicker: typeof QuarterPicker;
};
const MergedDatePicker = DatePicker as MergedDatePicker;
@ -145,6 +151,7 @@ function generatePicker<DateType>(generateConfig: GenerateConfig<DateType>) {
MergedDatePicker.YearPicker = YearPicker;
MergedDatePicker.RangePicker = RangePicker;
MergedDatePicker.TimePicker = TimePicker;
MergedDatePicker.QuarterPicker = QuarterPicker;
return MergedDatePicker;
}

View File

@ -16,11 +16,11 @@ By clicking the input box, you can select a date from a popup calendar.
There are five kinds of picker:
- DatePicker
- MonthPicker
- DatePicker\[picker="month"]
- DatePicker\[picker="week"]
- DatePicker\[picker="year"]
- DatePicker\[picker="quarter"] (Added in 4.1.0)
- RangePicker
- WeekPicker
- YearPicker
- QuarterPicker (Added in 4.1.0)
### Localization
@ -43,7 +43,7 @@ import moment from 'moment';
### Common API
The following APIs are shared by DatePicker, YearPicker, MonthPicker, RangePicker, WeekPicker.
The following APIs are shared by DatePicker, RangePicker.
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
@ -95,7 +95,7 @@ The following APIs are shared by DatePicker, YearPicker, MonthPicker, RangePicke
| onPanelChange | Callback function for panel changing | function(value, mode) | - | |
| showNow | Whether to show 'Now' button on panel when `showTime` is set | boolean | - | 4.4.0 |
### YearPicker
### DatePicker\[picker=year]
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
@ -106,7 +106,7 @@ The following APIs are shared by DatePicker, YearPicker, MonthPicker, RangePicke
| value | To set date | [moment](http://momentjs.com/) | - | |
| onChange | Callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - | |
### QuarterPicker
### DatePicker\[picker=quarter]
Added in `4.1.0`.
@ -119,7 +119,7 @@ Added in `4.1.0`.
| value | To set date | [moment](http://momentjs.com/) | - | |
| onChange | Callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - | |
### MonthPicker
### DatePicker\[picker=month]
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
@ -131,7 +131,7 @@ Added in `4.1.0`.
| value | To set date | [moment](http://momentjs.com/) | - | |
| onChange | Callback function, can be executed when the selected time is changing | function(date: moment, dateString: string) | - | |
### WeekPicker
### DatePicker\[picker=week]
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |

View File

@ -17,11 +17,11 @@ cover: https://gw.alipayobjects.com/zos/alicdn/RT_USzA48/DatePicker.svg
日期类组件包括以下五种形式。
- DatePicker
- MonthPicker
- DatePicker\[picker="month"]
- DatePicker\[picker="week"]
- DatePicker\[picker="year"]
- DatePicker\[picker="quarter"] (4.1.0 新增)
- RangePicker
- WeekPicker
- YearPicker
- QuarterPicker (4.1.0 新增)
### 国际化配置
@ -45,7 +45,7 @@ import 'moment/locale/zh-cn';
### 共同的 API
以下 API 为 DatePicker、YearPicker、MonthPicker、RangePicker, WeekPicker 共享的 API。
以下 API 为 DatePicker、 RangePicker 共享的 API。
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
@ -97,7 +97,7 @@ import 'moment/locale/zh-cn';
| onPanelChange | 日期面板变化时的回调 | function(value, mode) | - | |
| showNow | 当设定了 `showTime` 的时候,面板是否显示“此刻”按钮 | boolean | - | 4.4.0 |
### YearPicker
### DatePicker\[picker=year]
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
@ -108,7 +108,7 @@ import 'moment/locale/zh-cn';
| value | 日期 | [moment](http://momentjs.com/) | - | |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: moment, dateString: string) | - | |
### QuarterPicker
### DatePicker\[picker=quarter]
`4.1.0` 新增。
@ -121,7 +121,7 @@ import 'moment/locale/zh-cn';
| value | 日期 | [moment](http://momentjs.com/) | - | |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: moment, dateString: string) | - | |
### MonthPicker
### DatePicker\[picker=month]
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
@ -133,7 +133,7 @@ import 'moment/locale/zh-cn';
| value | 日期 | [moment](http://momentjs.com/) | - | |
| onChange | 时间发生变化的回调,发生在用户选择时间时 | function(date: moment, dateString: string) | - | |
### WeekPicker
### DatePicker\[picker=week]
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |

View File

@ -16,7 +16,7 @@ The `value` of time-related components is a `moment` object, which we need to pr
```tsx
import { Form, DatePicker, TimePicker, Button } from 'antd';
const { MonthPicker, RangePicker } = DatePicker;
const { RangePicker } = DatePicker;
const formItemLayout = {
labelCol: {
@ -64,7 +64,7 @@ const TimeRelatedForm = () => {
<DatePicker showTime format="YYYY-MM-DD HH:mm:ss" />
</Form.Item>
<Form.Item name="month-picker" label="MonthPicker" {...config}>
<MonthPicker />
<DatePicker picker="month" />
</Form.Item>
<Form.Item name="range-picker" label="RangePicker" {...rangeConfig}>
<RangePicker />

View File

@ -24,7 +24,7 @@ import {
const { Text } = Typography;
const { Option } = Select;
const { MonthPicker, RangePicker } = DatePicker;
const { RangePicker } = DatePicker;
const narrowStyle = {
width: 50,
@ -88,7 +88,7 @@ ReactDOM.render(
<TreeSelect style={{ width: 100 }} />
<Cascader defaultValue={['zhejiang', 'hangzhou', 'xihu']} options={options} />
<RangePicker />
<MonthPicker />
<DatePicker picker="month" />
<Radio.Group defaultValue="a">
<Radio.Button value="a">Hangzhou</Radio.Button>
<Radio.Button value="b">Shanghai</Radio.Button>

View File

@ -162,6 +162,7 @@ function notice(args: ArgsProps): MessageType {
}
return resolve(true);
};
getRCNotificationInstance(args, ({ prefixCls, instance }) => {
instance.notice(getRCNoticeProps({ ...args, key: target, onClose: callback }, prefixCls));
});

View File

@ -205,7 +205,7 @@ function getRCNoticeProps(args: ArgsProps, prefixCls: string) {
return {
content: (
<div className={iconNode ? `${prefixCls}-with-icon` : ''}>
<div className={iconNode ? `${prefixCls}-with-icon` : ''} role="alert">
{iconNode}
<div className={`${prefixCls}-message`}>
{autoMarginTag}

View File

@ -167,6 +167,7 @@
button {
color: @text-color;
cursor: pointer;
user-select: none;
}

View File

@ -62,6 +62,7 @@ exports[`renders ./components/spin/demo/delayAndDebounce.md correctly 1`] = `
<div
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -135,6 +136,7 @@ exports[`renders ./components/spin/demo/nested.md correctly 1`] = `
<div
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"
@ -288,6 +290,7 @@ exports[`renders ./components/spin/demo/tip.md correctly 1`] = `
<div
class="ant-alert ant-alert-info ant-alert-with-description ant-alert-no-icon"
data-show="true"
role="alert"
>
<span
class="ant-alert-message"

View File

@ -98,6 +98,7 @@ describe('Table.rowSelection', () => {
const rowSelection = {
getCheckboxProps: record => ({
disabled: record.name === 'Lucy',
indeterminate: record.name === 'Tom',
name: record.name,
}),
};
@ -109,6 +110,22 @@ describe('Table.rowSelection', () => {
expect(checkboxes.at(1).props().name).toEqual(data[0].name);
expect(checkboxes.at(2).props().disabled).toBe(true);
expect(checkboxes.at(2).props().name).toEqual(data[1].name);
expect(getIndeterminateSelection(wrapper)).toEqual([2]);
});
it("make getCheckboxProps's `indeterminate` override selectedRowKeys' effect", () => {
const rowSelection = {
getCheckboxProps: record => ({
disabled: record.name === 'Lucy',
indeterminate: record.name === 'Tom',
name: record.name,
}),
selectedRowKeys: [2],
};
const wrapper = mount(createTable({ rowSelection }));
expect(getIndeterminateSelection(wrapper)).toEqual([2]);
});
it('works with pagination', () => {
@ -1041,6 +1058,26 @@ describe('Table.rowSelection', () => {
expect(onChange.mock.calls[2][0]).toEqual(['Jerry Tom Tom']);
});
});
it('warns when set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured data.', () => {
resetWarned();
mount(
createTable({
dataSource: dataWithChildren,
defaultExpandAllRows: true,
rowSelection: {
checkStrictly: false,
getCheckboxProps() {
return {
indeterminate: true,
};
},
},
}),
);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Table] set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured dataSource.',
);
});
});
describe('cache with selected keys', () => {

View File

@ -5494,305 +5494,6 @@ exports[`renders ./components/table/demo/expand.md correctly 1`] = `
</div>
`;
exports[`renders ./components/table/demo/expand-children.md correctly 1`] = `
Array [
<div
class="ant-space ant-space-horizontal ant-space-align-center"
style="margin-bottom:16px"
>
<div
class="ant-space-item"
style="margin-right:8px"
>
CheckStrictly:
</div>
<div
class="ant-space-item"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
</div>,
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout:auto"
>
<colgroup>
<col
class="ant-table-selection-col"
/>
<col />
<col
style="width:12%;min-width:12%"
/>
<col
style="width:30%;min-width:30%"
/>
</colgroup>
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell ant-table-selection-column"
>
<div
class="ant-table-selection"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</div>
</th>
<th
class="ant-table-cell"
>
Name
</th>
<th
class="ant-table-cell"
>
Age
</th>
<th
class="ant-table-cell"
>
Address
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell ant-table-selection-column"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</td>
<td
class="ant-table-cell ant-table-cell-with-append"
>
<span
class="ant-table-row-indent indent-level-0"
style="padding-left:0px"
/>
<button
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
/>
John Brown sr.
</td>
<td
class="ant-table-cell"
>
60
</td>
<td
class="ant-table-cell"
>
New York No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell ant-table-selection-column"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</td>
<td
class="ant-table-cell ant-table-cell-with-append"
>
<span
class="ant-table-row-indent indent-level-0"
style="padding-left:0px"
/>
<button
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
/>
Joe Black
</td>
<td
class="ant-table-cell"
>
32
</td>
<td
class="ant-table-cell"
>
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
unselectable="unselectable"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</button>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a
rel="nofollow"
>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</button>
</li>
</ul>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/table/demo/fixed-columns.md correctly 1`] = `
<div
class="ant-table-wrapper"
@ -15769,6 +15470,305 @@ Array [
]
`;
exports[`renders ./components/table/demo/tree-data.md correctly 1`] = `
Array [
<div
class="ant-space ant-space-horizontal ant-space-align-center"
style="margin-bottom:16px"
>
<div
class="ant-space-item"
style="margin-right:8px"
>
CheckStrictly:
</div>
<div
class="ant-space-item"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
</div>,
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout:auto"
>
<colgroup>
<col
class="ant-table-selection-col"
/>
<col />
<col
style="width:12%;min-width:12%"
/>
<col
style="width:30%;min-width:30%"
/>
</colgroup>
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell ant-table-selection-column"
>
<div
class="ant-table-selection"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</div>
</th>
<th
class="ant-table-cell"
>
Name
</th>
<th
class="ant-table-cell"
>
Age
</th>
<th
class="ant-table-cell"
>
Address
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell ant-table-selection-column"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</td>
<td
class="ant-table-cell ant-table-cell-with-append"
>
<span
class="ant-table-row-indent indent-level-0"
style="padding-left:0px"
/>
<button
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
/>
John Brown sr.
</td>
<td
class="ant-table-cell"
>
60
</td>
<td
class="ant-table-cell"
>
New York No. 1 Lake Park
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell ant-table-selection-column"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</td>
<td
class="ant-table-cell ant-table-cell-with-append"
>
<span
class="ant-table-row-indent indent-level-0"
style="padding-left:0px"
/>
<button
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
/>
Joe Black
</td>
<td
class="ant-table-cell"
>
32
</td>
<td
class="ant-table-cell"
>
Sidney No. 1 Lake Park
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
unselectable="unselectable"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</button>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a
rel="nofollow"
>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<button
class="ant-pagination-item-link"
disabled=""
tabindex="-1"
type="button"
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</button>
</li>
</ul>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/table/demo/virtual-list.md correctly 1`] = `
<div
class="ant-table-wrapper virtual-table"

View File

@ -431,14 +431,25 @@ export default function useSelection<RecordType>(
const key = getRowKey(record, index);
const checked = keySet.has(key);
const indeterminate = derivedHalfSelectedKeySet.has(key);
const checkboxProps = checkboxPropsMap.get(key);
let mergedIndeterminate: boolean;
if (expandType === 'nest') {
mergedIndeterminate = indeterminate;
devWarning(
!(typeof checkboxProps?.indeterminate === 'boolean'),
'Table',
'set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured dataSource.',
);
} else {
mergedIndeterminate = checkboxProps?.indeterminate ?? indeterminate;
}
// Record checked
return {
node: (
<Checkbox
{...checkboxPropsMap.get(key)}
{...checkboxProps}
indeterminate={mergedIndeterminate}
checked={checked}
indeterminate={indeterminate}
onClick={e => e.stopPropagation()}
onChange={({ nativeEvent }) => {
const { shiftKey } = nativeEvent;

View File

@ -68,7 +68,7 @@ const columns = [
| expandable | Config expandable content | [expandable](#expandable) | - |
| footer | Table footer renderer | function(currentPageData) | - |
| loading | Loading status of table | boolean \| [object](/components/spin/#API) ([more](https://github.com/ant-design/ant-design/issues/4544#issuecomment-271533135)) | false |
| locale | The i18n text including filter, sort, empty text, etc | object | filterConfirm: `Ok` <br> filterReset: `Reset` <br> emptyText: `No Data` <br> [Default](https://github.com/ant-design/ant-design/issues/575#issuecomment-159169511) |
| locale | The i18n text including filter, sort, empty text, etc | object | filterConfirm: `Ok` <br> filterReset: `Reset` <br> emptyText: `No Data` <br> [Default](https://github.com/ant-design/ant-design/blob/4ad1ccac277782d7ed14f7e5d02d6346aae0db67/components/locale/default.tsx#L19) |
| pagination | Config of pagination. You can ref table pagination [config](#pagination) or full [`pagination`](/components/pagination/) document, hide it by setting it to `false` | object | - |
| rowClassName | Row's className | function(record, index): string | - |
| rowKey | Row's unique key, could be a string or function that returns a string | string \| function(record): string | `key` |

View File

@ -75,7 +75,7 @@ const columns = [
| expandable | 配置展开属性 | [expandable](#expandable) | - |
| footer | 表格尾部 | function(currentPageData) | - |
| loading | 页面是否加载中 | boolean \| [object](/components/spin/#API) ([更多](https://github.com/ant-design/ant-design/issues/4544#issuecomment-271533135)) | false |
| locale | 默认文案设置,目前包括排序、过滤、空数据文案 | object | filterConfirm: `确定` <br> filterReset: `重置` <br> emptyText: `暂无数据` <br> [默认值](https://github.com/ant-design/ant-design/issues/575#issuecomment-159169511) |
| locale | 默认文案设置,目前包括排序、过滤、空数据文案 | object | filterConfirm: `确定` <br> filterReset: `重置` <br> emptyText: `暂无数据` <br> [默认值](https://github.com/ant-design/ant-design/blob/4ad1ccac277782d7ed14f7e5d02d6346aae0db67/components/locale/default.tsx#L19) |
| pagination | 分页器,参考[配置项](#pagination)或 [pagination](/components/pagination/) 文档,设为 false 时不展示和进行分页 | object | - |
| rowClassName | 表格行的类名 | function(record, index): string | - |
| rowKey | 表格行 key 的取值,可以是字符串或一个函数 | string \| function(record): string | `key` |

View File

@ -73,3 +73,8 @@ Ant Design 团队会关注所有的 pull request我们会 review 以及合并
## 加入社区
如果你贡献度足够活跃,希望和 Ant Design 团队一起参与维护工作,你可以[申请成为社区协作者](https://github.com/ant-design/ant-design/wiki/Collaborators#how-to-apply-for-being-a-collaborator)。
你还可以参考下面两篇社区成员写的贡献指南,一步一步成为 antd 的贡献者吧:
- [记录向:如何快速的成为 Ant Design 的 contributor](https://zhuanlan.zhihu.com/p/123367842) [@Rustin-Liu](https://github.com/Rustin-Liu)
- [从 0 开始,成为 Ant-Design Contributor](https://zhuanlan.zhihu.com/p/143895612) [@fireairforce](https://github.com/fireairforce)

View File

@ -141,7 +141,7 @@
"rc-textarea": "~0.3.0",
"rc-tooltip": "~4.2.0",
"rc-tree": "~3.8.0",
"rc-tree-select": "~4.0.2",
"rc-tree-select": "~4.1.0",
"rc-trigger": "~4.3.0",
"rc-upload": "~3.2.0",
"rc-util": "^5.0.1",
@ -166,6 +166,7 @@
"@types/raf": "^3.4.0",
"@types/react": "^16.9.21",
"@types/react-color": "^3.0.1",
"@types/react-copy-to-clipboard": "^4.3.0",
"@types/react-dom": "^16.9.5",
"@types/warning": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^3.0.0",
@ -277,6 +278,7 @@
"theme-switcher": "^1.0.2",
"typescript": "~3.9.2",
"webpack-bundle-analyzer": "^3.6.0",
"webpack": "~4.43.0",
"xhr-mock": "^2.4.1",
"xhr2": "^0.2.0",
"yaml-front-matter": "^4.0.0"

View File

@ -18,39 +18,39 @@ const SourceImages = {
const MORE_LIST: MoreProps[] = [
{
title: '编辑器设计系列:每天都在用,你真的了解它么?',
title: '设计考古:工具类产品 Office',
description:
'提起编辑器,你会想到什么?也许你从来没有意识到,但是从接触计算机开始,你就和各种编辑器打上了交道。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*c88yR4TO1z8AAAAAAAAAAABkARQnAQ',
date: '2020-04-15',
'微软 Office 办公系列产品的精髓在于 Ribbon功能区设计模式它很好的解决了文档类、工具类复杂产品的高交互密度设计难题。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*nJogR776K8EAAAAAAAAAAABkARQnAQ',
date: '2019-11-05',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/113961511',
href: 'https://zhuanlan.zhihu.com/p/90304083',
},
{
title: '让价值被发现:如何在 B 端做增长',
title: '数据可视化的驱动与使能',
description:
'在蚂蚁体验技术部,我们除了做好体验设计的「老本行」外,也在现有的增长理论指导下,结合自身业务,边落地实践,边沉淀总结。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*6ZajSKDM3MMAAAAAAAAAAABkARQnAQ',
date: '2020-01-17',
'“指哪打哪”形容听从驱使。在数据可视化设计中,操作“听从驱使”的可视化作品又是一种什么样的体验呢?',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*kGFrS4JCGo8AAAAAAAAAAABkARQnAQ',
date: '2019-10-30',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/103093131',
href: 'https://zhuanlan.zhihu.com/p/89352118',
},
{
title: '蚂蚁前端研发最佳实践',
title: '【AntV 关系图编辑器】交互设计沉思录',
description:
'本文介绍了蚂蚁前端研发的最佳实践,其中提取了三个比较重要的点,每个点都是我们实践和深入思考后的结果,希望能对大家有所启发。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*eHjqRLpxlcsAAAAAAAAAAABkARQnAQ',
date: '2019-12-03',
'AntV 是 Ant Design 设计语言中的可视化部分。本文讲述的是关系型数据 G6 中流程图编辑器的搭建经验。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1fTSTKxbOqAAAAAAAAAAAABkARQnAQ',
date: '2019-09-11',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/94949118',
href: 'https://zhuanlan.zhihu.com/p/82146871',
},
{
title: '“炫酷狂拽”的 AntV - L7 地图可视化设计',
description: '不忘初心方致千里L7 从「心」出发,知设计体系之源,致地图可视化设计之远。本文揭秘 L7 这次探寻之旅中的 4 大发现。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*dGj_Tq9PtPMAAAAAAAAAAABkARQnAQ',
date: '2019-11-28',
title: '设计法则「映射」: 让你的设计更符合直觉',
description: '影响一个东西好不好用的因素有很多本文将从125条通用设计法则中的「映射Mapping」出发探讨一下这个法则对事物可用性的影响。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*AVELR486CNcAAAAAAAAAAABkARQnAQ',
date: '2019-08-24',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/94203386',
href: 'https://zhuanlan.zhihu.com/p/79632824',
},
];

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import { Badge } from 'antd';
import { Badge, message } from 'antd';
import classNames from 'classnames';
import * as AntdIcons from '@ant-design/icons';
import { ThemeType } from './index';
@ -28,8 +28,15 @@ const CopyableIcon: React.FC<CopyableIconProps> = ({
copied: justCopied === name,
[theme]: !!theme,
});
const onCopy = (text: string, result: boolean) => {
if (result) {
onCopied(name, text);
} else {
message.error('Copy icon name failed, please try again.');
}
};
return (
<CopyToClipboard text={`<${name} />`} onCopy={(text: string) => onCopied(name, text)}>
<CopyToClipboard text={`<${name} />`} onCopy={onCopy}>
<li className={className}>
{React.createElement(allIcons[name])}
<span className="anticon-class">

View File

@ -68,6 +68,9 @@ class IconDisplay extends React.PureComponent<IconDisplayProps, IconDisplayState
);
}
// CopyrightCircle is same as Copyright, don't show it
iconList = iconList.filter(icon => icon !== 'CopyrightCircle');
return {
category: key,
icons: iconList.map(iconName => iconName + theme).filter(iconName => allIcons[iconName]),

View File

@ -65,5 +65,3 @@ declare module '*.json' {
export const version: string;
export default value;
}
declare module 'react-copy-to-clipboard';