mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-06 16:06:28 +08:00
Merge branch 'master' of github.com:ant-design/ant-design
This commit is contained in:
commit
ac14f44f2b
@ -38,9 +38,9 @@ An enterprise-class UI design language and React UI library.
|
||||
[help-wanted-url]: https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
|
||||
[twitter-image]: https://img.shields.io/twitter/follow/AntDesignUI.svg?label=Ant%20Design&style=social
|
||||
[twitter-url]: https://twitter.com/AntDesignUI
|
||||
[gitter-english-image]: https://img.shields.io/gitter/room/ant-design/ant-design-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D
|
||||
[gitter-english-image]: https://img.shields.io/gitter/room/ant-design/ant-design-english.svg?style=flat-square&logoWidth=18&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D
|
||||
[gitter-english-url]: https://gitter.im/ant-design/ant-design-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
|
||||
[gitter-chinese-image]: https://img.shields.io/gitter/room/ant-design/ant-design.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D
|
||||
[gitter-chinese-image]: https://img.shields.io/gitter/room/ant-design/ant-design.svg?style=flat-square&logoWidth=18&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D
|
||||
[gitter-chinese-url]: https://gitter.im/ant-design/ant-design?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
[semver-stability-url]: https://dependabot.com/compatibility-score.html/?dependency-name=antd&package-manager=npm_and_yarn&new-version=latest
|
||||
[semver-stability-image]: https://api.dependabot.com/badges/compatibility_score?dependency-name=antd&package-manager=npm_and_yarn&target-version=latest&version-scheme=semver
|
||||
|
@ -50,73 +50,50 @@ export interface ScrollNumberState {
|
||||
count?: string | number | null;
|
||||
}
|
||||
|
||||
class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState> {
|
||||
static defaultProps = {
|
||||
count: null,
|
||||
onAnimated() {},
|
||||
};
|
||||
const ScrollNumber: React.FC<ScrollNumberProps> = props => {
|
||||
const [animateStarted, setAnimateStarted] = React.useState(true);
|
||||
const [count, setCount] = React.useState(props.count);
|
||||
const [prevCount, setPrevCount] = React.useState(props.count);
|
||||
const [lastCount, setLastCount] = React.useState(props.count);
|
||||
|
||||
static getDerivedStateFromProps(nextProps: ScrollNumberProps, nextState: ScrollNumberState) {
|
||||
if ('count' in nextProps) {
|
||||
if (nextState.count === nextProps.count) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
animateStarted: true,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
if (prevCount !== props.count) {
|
||||
setAnimateStarted(true);
|
||||
setPrevCount(props.count);
|
||||
}
|
||||
|
||||
lastCount?: string | number | null;
|
||||
|
||||
private timeout?: number;
|
||||
|
||||
constructor(props: ScrollNumberProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
animateStarted: true,
|
||||
count: props.count,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(_: any, prevState: ScrollNumberState) {
|
||||
this.lastCount = prevState.count;
|
||||
const { animateStarted } = this.state;
|
||||
React.useEffect(() => {
|
||||
setLastCount(count);
|
||||
let timeout: number;
|
||||
if (animateStarted) {
|
||||
this.clearTimeout();
|
||||
// Let browser has time to reset the scroller before actually
|
||||
// performing the transition.
|
||||
this.timeout = setTimeout(() => {
|
||||
// eslint-disable-next-line react/no-did-update-set-state
|
||||
this.setState(
|
||||
(__, props) => ({
|
||||
animateStarted: false,
|
||||
count: props.count,
|
||||
}),
|
||||
this.onAnimated,
|
||||
);
|
||||
timeout = setTimeout(() => {
|
||||
setAnimateStarted(false);
|
||||
setCount(props.count);
|
||||
if (props.onAnimated) {
|
||||
props.onAnimated();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
};
|
||||
}, [animateStarted, count, props.count, props.onAnimated]);
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearTimeout();
|
||||
}
|
||||
|
||||
getPositionByNum(num: number, i: number) {
|
||||
const { count } = this.state;
|
||||
const getPositionByNum = (num: number, i: number) => {
|
||||
const currentCount = Math.abs(Number(count));
|
||||
const lastCount = Math.abs(Number(this.lastCount));
|
||||
const currentDigit = Math.abs(getNumberArray(this.state.count)[i] as number);
|
||||
const lastDigit = Math.abs(getNumberArray(this.lastCount)[i] as number);
|
||||
const lstCount = Math.abs(Number(lastCount));
|
||||
const currentDigit = Math.abs(getNumberArray(count)[i] as number);
|
||||
const lastDigit = Math.abs(getNumberArray(lstCount)[i] as number);
|
||||
|
||||
if (this.state.animateStarted) {
|
||||
if (animateStarted) {
|
||||
return 10 + num;
|
||||
}
|
||||
|
||||
// 同方向则在同一侧切换数字
|
||||
if (currentCount > lastCount) {
|
||||
if (currentCount > lstCount) {
|
||||
if (currentDigit >= lastDigit) {
|
||||
return 10 + num;
|
||||
}
|
||||
@ -126,20 +103,12 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
|
||||
return 10 + num;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
onAnimated = () => {
|
||||
const { onAnimated } = this.props;
|
||||
if (onAnimated) {
|
||||
onAnimated();
|
||||
}
|
||||
};
|
||||
|
||||
renderCurrentNumber(prefixCls: string, num: number | string, i: number) {
|
||||
const renderCurrentNumber = (prefixCls: string, num: number | string, i: number) => {
|
||||
if (typeof num === 'number') {
|
||||
const position = this.getPositionByNum(num, i);
|
||||
const removeTransition =
|
||||
this.state.animateStarted || getNumberArray(this.lastCount)[i] === undefined;
|
||||
const position = getPositionByNum(num, i);
|
||||
const removeTransition = animateStarted || getNumberArray(lastCount)[i] === undefined;
|
||||
return React.createElement(
|
||||
'span',
|
||||
{
|
||||
@ -161,19 +130,18 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
|
||||
{num}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderNumberElement(prefixCls: string) {
|
||||
const { count } = this.state;
|
||||
const renderNumberElement = (prefixCls: string) => {
|
||||
if (count && Number(count) % 1 === 0) {
|
||||
return getNumberArray(count)
|
||||
.map((num, i) => this.renderCurrentNumber(prefixCls, num, i))
|
||||
.map((num, i) => renderCurrentNumber(prefixCls, num, i))
|
||||
.reverse();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
renderScrollNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const renderScrollNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
@ -181,9 +149,9 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
|
||||
title,
|
||||
component = 'sup',
|
||||
displayComponent,
|
||||
} = this.props;
|
||||
} = props;
|
||||
// fix https://fb.me/react-unknown-prop
|
||||
const restProps = omit(this.props, [
|
||||
const restProps = omit(props, [
|
||||
'count',
|
||||
'onAnimated',
|
||||
'component',
|
||||
@ -214,19 +182,15 @@ class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState>
|
||||
),
|
||||
});
|
||||
}
|
||||
return React.createElement(component as any, newProps, this.renderNumberElement(prefixCls));
|
||||
return React.createElement(component as any, newProps, renderNumberElement(prefixCls));
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderScrollNumber}</ConfigConsumer>;
|
||||
}
|
||||
return <ConfigConsumer>{renderScrollNumber}</ConfigConsumer>;
|
||||
};
|
||||
|
||||
private clearTimeout(): void {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
ScrollNumber.defaultProps = {
|
||||
count: null,
|
||||
onAnimated() {},
|
||||
};
|
||||
|
||||
export default ScrollNumber;
|
||||
|
@ -32,40 +32,47 @@ function isPresetColor(color?: string): boolean {
|
||||
return (PresetColorTypes as any[]).indexOf(color) !== -1;
|
||||
}
|
||||
|
||||
export default class Badge extends React.Component<BadgeProps, any> {
|
||||
static defaultProps = {
|
||||
count: null,
|
||||
showZero: false,
|
||||
dot: false,
|
||||
overflowCount: 99,
|
||||
};
|
||||
|
||||
getNumberedDisplayCount() {
|
||||
const { count, overflowCount } = this.props;
|
||||
const Badge: React.FC<BadgeProps> = props => {
|
||||
const getNumberedDisplayCount = () => {
|
||||
const { count, overflowCount } = props;
|
||||
const displayCount =
|
||||
(count as number) > (overflowCount as number) ? `${overflowCount}+` : count;
|
||||
return displayCount as string | number | null;
|
||||
}
|
||||
};
|
||||
|
||||
getDisplayCount() {
|
||||
const isDot = this.isDot();
|
||||
const hasStatus = (): boolean => {
|
||||
const { status, color } = props;
|
||||
return !!status || !!color;
|
||||
};
|
||||
|
||||
const isZero = () => {
|
||||
const numberedDisplayCount = getNumberedDisplayCount();
|
||||
return numberedDisplayCount === '0' || numberedDisplayCount === 0;
|
||||
};
|
||||
|
||||
const isDot = () => {
|
||||
const { dot } = props;
|
||||
return (dot && !isZero()) || hasStatus();
|
||||
};
|
||||
|
||||
const getDisplayCount = () => {
|
||||
// dot mode don't need count
|
||||
if (isDot) {
|
||||
if (isDot()) {
|
||||
return '';
|
||||
}
|
||||
return this.getNumberedDisplayCount();
|
||||
}
|
||||
return getNumberedDisplayCount();
|
||||
};
|
||||
|
||||
getScrollNumberTitle() {
|
||||
const { title, count } = this.props;
|
||||
const getScrollNumberTitle = () => {
|
||||
const { title, count } = props;
|
||||
if (title) {
|
||||
return title;
|
||||
}
|
||||
return typeof count === 'string' || typeof count === 'number' ? count : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
getStyleWithOffset() {
|
||||
const { offset, style } = this.props;
|
||||
const getStyleWithOffset = () => {
|
||||
const { offset, style } = props;
|
||||
return offset
|
||||
? {
|
||||
right: -parseInt(offset[0] as string, 10),
|
||||
@ -73,79 +80,61 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
...style,
|
||||
}
|
||||
: style;
|
||||
}
|
||||
};
|
||||
|
||||
getBadgeClassName(prefixCls: string, direction: string = 'ltr') {
|
||||
const { className, children } = this.props;
|
||||
const getBadgeClassName = (prefixCls: string, direction: string = 'ltr') => {
|
||||
const { className, children } = props;
|
||||
return classNames(className, prefixCls, {
|
||||
[`${prefixCls}-status`]: this.hasStatus(),
|
||||
[`${prefixCls}-status`]: hasStatus(),
|
||||
[`${prefixCls}-not-a-wrapper`]: !children,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
}) as string;
|
||||
}
|
||||
};
|
||||
|
||||
hasStatus(): boolean {
|
||||
const { status, color } = this.props;
|
||||
return !!status || !!color;
|
||||
}
|
||||
|
||||
isZero() {
|
||||
const numberedDisplayCount = this.getNumberedDisplayCount();
|
||||
return numberedDisplayCount === '0' || numberedDisplayCount === 0;
|
||||
}
|
||||
|
||||
isDot() {
|
||||
const { dot } = this.props;
|
||||
const isZero = this.isZero();
|
||||
return (dot && !isZero) || this.hasStatus();
|
||||
}
|
||||
|
||||
isHidden() {
|
||||
const { showZero } = this.props;
|
||||
const displayCount = this.getDisplayCount();
|
||||
const isZero = this.isZero();
|
||||
const isDot = this.isDot();
|
||||
const isHidden = () => {
|
||||
const { showZero } = props;
|
||||
const displayCount = getDisplayCount();
|
||||
const isEmpty = displayCount === null || displayCount === undefined || displayCount === '';
|
||||
return (isEmpty || (isZero && !showZero)) && !isDot;
|
||||
}
|
||||
return (isEmpty || (isZero() && !showZero)) && !isDot();
|
||||
};
|
||||
|
||||
renderStatusText(prefixCls: string) {
|
||||
const { text } = this.props;
|
||||
const hidden = this.isHidden();
|
||||
const renderStatusText = (prefixCls: string) => {
|
||||
const { text } = props;
|
||||
const hidden = isHidden();
|
||||
return hidden || !text ? null : <span className={`${prefixCls}-status-text`}>{text}</span>;
|
||||
}
|
||||
};
|
||||
|
||||
renderDisplayComponent() {
|
||||
const { count } = this.props;
|
||||
const renderDisplayComponent = () => {
|
||||
const { count } = props;
|
||||
const customNode = count as React.ReactElement<any>;
|
||||
if (!customNode || typeof customNode !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
return React.cloneElement(customNode, {
|
||||
style: {
|
||||
...this.getStyleWithOffset(),
|
||||
...getStyleWithOffset(),
|
||||
...(customNode.props && customNode.props.style),
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
renderBadgeNumber(prefixCls: string, scrollNumberPrefixCls: string) {
|
||||
const { status, count, color } = this.props;
|
||||
const renderBadgeNumber = (prefixCls: string, scrollNumberPrefixCls: string) => {
|
||||
const { status, count, color } = props;
|
||||
|
||||
const displayCount = this.getDisplayCount();
|
||||
const isDot = this.isDot();
|
||||
const hidden = this.isHidden();
|
||||
const displayCount = getDisplayCount();
|
||||
const dot = isDot();
|
||||
const hidden = isHidden();
|
||||
|
||||
const scrollNumberCls = classNames({
|
||||
[`${prefixCls}-dot`]: isDot,
|
||||
[`${prefixCls}-count`]: !isDot,
|
||||
[`${prefixCls}-dot`]: dot,
|
||||
[`${prefixCls}-count`]: !dot,
|
||||
[`${prefixCls}-multiple-words`]:
|
||||
!isDot && count && count.toString && count.toString().length > 1,
|
||||
!dot && count && count.toString && count.toString().length > 1,
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-status-${color}`]: isPresetColor(color),
|
||||
});
|
||||
|
||||
let statusStyle: React.CSSProperties | undefined = this.getStyleWithOffset();
|
||||
let statusStyle: React.CSSProperties | undefined = getStyleWithOffset();
|
||||
if (color && !isPresetColor(color)) {
|
||||
statusStyle = statusStyle || {};
|
||||
statusStyle.background = color;
|
||||
@ -157,15 +146,15 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
data-show={!hidden}
|
||||
className={scrollNumberCls}
|
||||
count={displayCount}
|
||||
displayComponent={this.renderDisplayComponent()} // <Badge status="success" count={<Icon type="xxx" />}></Badge>
|
||||
title={this.getScrollNumberTitle()}
|
||||
displayComponent={renderDisplayComponent()} // <Badge status="success" count={<Icon type="xxx" />}></Badge>
|
||||
title={getScrollNumberTitle()}
|
||||
style={statusStyle}
|
||||
key="scrollNumber"
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderBadge = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const renderBadge = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
|
||||
@ -174,7 +163,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
text,
|
||||
color,
|
||||
...restProps
|
||||
} = this.props;
|
||||
} = props;
|
||||
const omitArr = [
|
||||
'count',
|
||||
'showZero',
|
||||
@ -189,11 +178,11 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
const prefixCls = getPrefixCls('badge', customizePrefixCls);
|
||||
const scrollNumberPrefixCls = getPrefixCls('scroll-number', customizeScrollNumberPrefixCls);
|
||||
|
||||
const scrollNumber = this.renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
|
||||
const statusText = this.renderStatusText(prefixCls);
|
||||
const scrollNumber = renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
|
||||
const statusText = renderStatusText(prefixCls);
|
||||
|
||||
const statusCls = classNames({
|
||||
[`${prefixCls}-status-dot`]: this.hasStatus(),
|
||||
[`${prefixCls}-status-dot`]: hasStatus(),
|
||||
[`${prefixCls}-status-${status}`]: !!status,
|
||||
[`${prefixCls}-status-${color}`]: isPresetColor(color),
|
||||
});
|
||||
@ -203,13 +192,13 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
}
|
||||
|
||||
// <Badge status="success" />
|
||||
if (!children && this.hasStatus()) {
|
||||
const styleWithOffset = this.getStyleWithOffset();
|
||||
if (!children && hasStatus()) {
|
||||
const styleWithOffset = getStyleWithOffset();
|
||||
const statusTextColor = styleWithOffset && styleWithOffset.color;
|
||||
return (
|
||||
<span
|
||||
{...omit(restProps, omitArr)}
|
||||
className={this.getBadgeClassName(prefixCls, direction)}
|
||||
className={getBadgeClassName(prefixCls, direction)}
|
||||
style={styleWithOffset}
|
||||
>
|
||||
<span className={statusCls} style={statusStyle} />
|
||||
@ -221,7 +210,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
}
|
||||
|
||||
return (
|
||||
<span {...omit(restProps, omitArr)} className={this.getBadgeClassName(prefixCls, direction)}>
|
||||
<span {...omit(restProps, omitArr)} className={getBadgeClassName(prefixCls, direction)}>
|
||||
{children}
|
||||
<Animate
|
||||
component=""
|
||||
@ -236,7 +225,14 @@ export default class Badge extends React.Component<BadgeProps, any> {
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderBadge}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
return <ConfigConsumer>{renderBadge}</ConfigConsumer>;
|
||||
};
|
||||
|
||||
Badge.defaultProps = {
|
||||
count: null,
|
||||
showZero: false,
|
||||
dot: false,
|
||||
overflowCount: 99,
|
||||
};
|
||||
|
||||
export default Badge;
|
||||
|
28
components/config-provider/__tests__/container.test.js
Normal file
28
components/config-provider/__tests__/container.test.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import ConfigProvider from '..';
|
||||
import DatePicker from '../../date-picker';
|
||||
import Slider from '../../slider';
|
||||
|
||||
describe('ConfigProvider.GetPopupContainer', () => {
|
||||
it('Datepicker', () => {
|
||||
const getPopupContainer = jest.fn(node => node.parentNode);
|
||||
mount(
|
||||
<ConfigProvider getPopupContainer={getPopupContainer}>
|
||||
<DatePicker open />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(getPopupContainer).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Slider', () => {
|
||||
const getPopupContainer = jest.fn(node => node.parentNode);
|
||||
const wrapper = mount(
|
||||
<ConfigProvider getPopupContainer={getPopupContainer}>
|
||||
<Slider />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
wrapper.find('.ant-slider-handle').first().simulate('mouseenter');
|
||||
expect(getPopupContainer).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -49,9 +49,10 @@ export default function generateRangePicker<DateType>(
|
||||
};
|
||||
|
||||
renderPicker = (locale: PickerLocale) => {
|
||||
const { getPrefixCls, direction } = this.context;
|
||||
const { getPrefixCls, direction, getPopupContainer } = this.context;
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
getPopupContainer: customGetPopupContainer,
|
||||
className,
|
||||
size: customizeSize,
|
||||
bordered = true,
|
||||
@ -94,6 +95,7 @@ export default function generateRangePicker<DateType>(
|
||||
{...additionalOverrideProps}
|
||||
locale={locale!.lang}
|
||||
prefixCls={prefixCls}
|
||||
getPopupContainer={customGetPopupContainer || getPopupContainer}
|
||||
generateConfig={generateConfig}
|
||||
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
|
||||
nextIcon={<span className={`${prefixCls}-next-icon`} />}
|
||||
|
@ -62,9 +62,10 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
|
||||
};
|
||||
|
||||
renderPicker = (locale: PickerLocale) => {
|
||||
const { getPrefixCls, direction } = this.context;
|
||||
const { getPrefixCls, direction, getPopupContainer } = this.context;
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
getPopupContainer: customizeGetPopupContainer,
|
||||
className,
|
||||
size: customizeSize,
|
||||
bordered = true,
|
||||
@ -115,6 +116,7 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
})}
|
||||
prefixCls={prefixCls}
|
||||
getPopupContainer={customizeGetPopupContainer || getPopupContainer}
|
||||
generateConfig={generateConfig}
|
||||
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
|
||||
nextIcon={<span className={`${prefixCls}-next-icon`} />}
|
||||
|
@ -5,7 +5,7 @@ import RcHandle from 'rc-slider/lib/Handle';
|
||||
import classNames from 'classnames';
|
||||
import { TooltipPlacement } from '../tooltip';
|
||||
import SliderTooltip from './SliderTooltip';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
export interface SliderMarks {
|
||||
[key: number]:
|
||||
@ -60,6 +60,7 @@ export interface SliderProps {
|
||||
export type Visibles = { [index: number]: boolean };
|
||||
|
||||
const Slider = React.forwardRef<unknown, SliderProps>((props, ref) => {
|
||||
const { getPrefixCls, direction, getPopupContainer } = React.useContext(ConfigContext);
|
||||
const [visibles, setVisibles] = React.useState<Visibles>({});
|
||||
|
||||
const toggleTooltipVisible = (index: number, visible: boolean) => {
|
||||
@ -91,7 +92,7 @@ const Slider = React.forwardRef<unknown, SliderProps>((props, ref) => {
|
||||
transitionName="zoom-down"
|
||||
key={index}
|
||||
overlayClassName={`${prefixCls}-tooltip`}
|
||||
getPopupContainer={getTooltipPopupContainer || (() => document.body)}
|
||||
getPopupContainer={getTooltipPopupContainer || getPopupContainer || (() => document.body)}
|
||||
>
|
||||
<RcHandle
|
||||
{...restProps}
|
||||
@ -102,44 +103,25 @@ const Slider = React.forwardRef<unknown, SliderProps>((props, ref) => {
|
||||
</SliderTooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const renderSlider = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
tooltipPrefixCls: customizeTooltipPrefixCls,
|
||||
range,
|
||||
className,
|
||||
...restProps
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('slider', customizePrefixCls);
|
||||
const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
|
||||
const cls = classNames(className, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
// make reverse default on rtl direction
|
||||
if (direction === 'rtl' && !restProps.vertical) {
|
||||
restProps.reverse = !restProps.reverse;
|
||||
}
|
||||
if (range) {
|
||||
return (
|
||||
<RcRange
|
||||
{...restProps}
|
||||
className={cls}
|
||||
ref={ref}
|
||||
handle={(info: HandleGeneratorInfo) =>
|
||||
handleWithTooltip({
|
||||
tooltipPrefixCls,
|
||||
prefixCls,
|
||||
info,
|
||||
})
|
||||
}
|
||||
prefixCls={prefixCls}
|
||||
tooltipPrefixCls={tooltipPrefixCls}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
tooltipPrefixCls: customizeTooltipPrefixCls,
|
||||
range,
|
||||
className,
|
||||
...restProps
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('slider', customizePrefixCls);
|
||||
const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
|
||||
const cls = classNames(className, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
// make reverse default on rtl direction
|
||||
if (direction === 'rtl' && !restProps.vertical) {
|
||||
restProps.reverse = !restProps.reverse;
|
||||
}
|
||||
if (range) {
|
||||
return (
|
||||
<RcSlider
|
||||
<RcRange
|
||||
{...restProps}
|
||||
className={cls}
|
||||
ref={ref}
|
||||
@ -154,11 +136,27 @@ const Slider = React.forwardRef<unknown, SliderProps>((props, ref) => {
|
||||
tooltipPrefixCls={tooltipPrefixCls}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return <ConfigConsumer>{renderSlider}</ConfigConsumer>;
|
||||
}
|
||||
return (
|
||||
<RcSlider
|
||||
{...restProps}
|
||||
className={cls}
|
||||
ref={ref}
|
||||
handle={(info: HandleGeneratorInfo) =>
|
||||
handleWithTooltip({
|
||||
tooltipPrefixCls,
|
||||
prefixCls,
|
||||
info,
|
||||
})
|
||||
}
|
||||
prefixCls={prefixCls}
|
||||
tooltipPrefixCls={tooltipPrefixCls}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Slider.displayName = 'Slider';
|
||||
|
||||
Slider.defaultProps = {
|
||||
tipFormatter(value: number) {
|
||||
return typeof value === 'number' ? value.toString() : '';
|
||||
|
@ -191,7 +191,7 @@
|
||||
"eslint-plugin-markdown": "^1.0.0",
|
||||
"eslint-plugin-react": "^7.14.2",
|
||||
"eslint-plugin-react-hooks": "^3.0.0",
|
||||
"eslint-plugin-unicorn": "^18.0.1",
|
||||
"eslint-plugin-unicorn": "^19.0.0",
|
||||
"eslint-tinker": "^0.5.0",
|
||||
"fetch-jsonp": "^1.1.3",
|
||||
"fs-extra": "^9.0.0",
|
||||
|
Loading…
Reference in New Issue
Block a user