mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-30 11:08:45 +08:00
fix[BackTop]: delete visible & use visibilityHeight=0 replace visible (#38763)
* type: delete visible & code optimization * add PureBackTop * fix: update snap * fix: cov * fix: add istanbul ignore * fix * feat: use visibilityHeight=0 replace visible=true * snap * cov * test case * test case * fix * fix cov * fix test * simplify code * rename function
This commit is contained in:
parent
618662a6d2
commit
0c3ba124b4
@ -5,47 +5,42 @@ import rtlTest from '../../../tests/shared/rtlTest';
|
|||||||
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||||
|
|
||||||
describe('BackTop', () => {
|
describe('BackTop', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
mountTest(BackTop);
|
mountTest(BackTop);
|
||||||
rtlTest(BackTop);
|
rtlTest(BackTop);
|
||||||
|
|
||||||
it('should scroll to top after click it', async () => {
|
it('should scroll to top after click it', async () => {
|
||||||
jest.useFakeTimers();
|
const { container } = render(<BackTop />);
|
||||||
|
|
||||||
const { container } = render(<BackTop visibilityHeight={-1} />);
|
|
||||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
||||||
window.scrollY = y;
|
window.scrollY = y;
|
||||||
window.pageYOffset = y;
|
window.pageYOffset = y;
|
||||||
document.documentElement.scrollTop = y;
|
document.documentElement.scrollTop = y;
|
||||||
});
|
});
|
||||||
window.scrollTo(0, 400);
|
window.scrollTo(0, 400);
|
||||||
|
await waitFakeTimer();
|
||||||
expect(document.documentElement.scrollTop).toBe(400);
|
expect(document.documentElement.scrollTop).toBe(400);
|
||||||
fireEvent.click(container.querySelector('.ant-back-top')!);
|
fireEvent.click(container.querySelector<HTMLDivElement>('.ant-back-top')!);
|
||||||
await waitFakeTimer();
|
await waitFakeTimer();
|
||||||
expect(document.documentElement.scrollTop).toBe(0);
|
expect(document.documentElement.scrollTop).toBe(0);
|
||||||
scrollToSpy.mockRestore();
|
scrollToSpy.mockRestore();
|
||||||
|
|
||||||
jest.clearAllTimers();
|
|
||||||
jest.useRealTimers();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('support onClick', async () => {
|
it('support onClick', () => {
|
||||||
const onClick = jest.fn();
|
const onClick = jest.fn();
|
||||||
const { container } = render(<BackTop onClick={onClick} visibilityHeight={-1} />);
|
const { container } = render(<BackTop onClick={onClick} visibilityHeight={0} />);
|
||||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
fireEvent.click(container.querySelector<HTMLDivElement>('.ant-back-top')!);
|
||||||
window.scrollY = y;
|
|
||||||
window.pageYOffset = y;
|
|
||||||
});
|
|
||||||
document.dispatchEvent(new Event('scroll'));
|
|
||||||
window.scrollTo(0, 400);
|
|
||||||
fireEvent.click(container.querySelector('.ant-back-top')!);
|
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
scrollToSpy.mockRestore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid target', async () => {
|
it('invalid target', () => {
|
||||||
const onClick = jest.fn();
|
const onClick = jest.fn();
|
||||||
const { container } = render(<BackTop onClick={onClick} visible target={undefined} />);
|
const { container } = render(<BackTop onClick={onClick} target={undefined} />);
|
||||||
fireEvent.click(container.querySelector('.ant-back-top')!);
|
fireEvent.click(container.querySelector<HTMLDivElement>('.ant-back-top')!);
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
it('should console Error', () => {
|
it('should console Error', () => {
|
||||||
|
@ -2,9 +2,9 @@ import VerticalAlignTopOutlined from '@ant-design/icons/VerticalAlignTopOutlined
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import CSSMotion from 'rc-motion';
|
import CSSMotion from 'rc-motion';
|
||||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
|
||||||
import omit from 'rc-util/lib/omit';
|
import omit from 'rc-util/lib/omit';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import type { ConfigConsumerProps } from '../config-provider';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
import getScroll from '../_util/getScroll';
|
import getScroll from '../_util/getScroll';
|
||||||
import { cloneElement } from '../_util/reactNode';
|
import { cloneElement } from '../_util/reactNode';
|
||||||
@ -22,62 +22,36 @@ export interface BackTopProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
visible?: boolean; // Only for test. Don't use it.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChildrenProps {
|
|
||||||
prefixCls: string;
|
|
||||||
rootPrefixCls: string;
|
|
||||||
children?: React.ReactNode;
|
|
||||||
visible?: boolean; // Only for test. Don't use it.
|
|
||||||
}
|
|
||||||
|
|
||||||
const BackTopContent: React.FC<ChildrenProps> = (props) => {
|
|
||||||
const { prefixCls, rootPrefixCls, children, visible } = props;
|
|
||||||
const defaultElement = (
|
|
||||||
<div className={`${prefixCls}-content`}>
|
|
||||||
<div className={`${prefixCls}-icon`}>
|
|
||||||
<VerticalAlignTopOutlined />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
|
|
||||||
{({ className: motionClassName }) =>
|
|
||||||
cloneElement(children || defaultElement, ({ className }) => ({
|
|
||||||
className: classNames(motionClassName, className),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
</CSSMotion>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BackTop: React.FC<BackTopProps> = (props) => {
|
const BackTop: React.FC<BackTopProps> = (props) => {
|
||||||
const [visible, setVisible] = useMergedState(false, {
|
const {
|
||||||
value: props.visible,
|
prefixCls: customizePrefixCls,
|
||||||
});
|
className = '',
|
||||||
|
visibilityHeight = 400,
|
||||||
|
target,
|
||||||
|
onClick,
|
||||||
|
duration = 450,
|
||||||
|
} = props;
|
||||||
|
const [visible, setVisible] = React.useState<boolean>(visibilityHeight === 0);
|
||||||
|
|
||||||
const ref = React.createRef<HTMLDivElement>();
|
const ref = React.useRef<HTMLDivElement>(null);
|
||||||
const scrollEvent = React.useRef<ReturnType<typeof addEventListener>>(null);
|
const scrollEvent = React.useRef<ReturnType<typeof addEventListener> | null>(null);
|
||||||
|
|
||||||
const getDefaultTarget = () =>
|
const getDefaultTarget = (): HTMLElement | Document | Window =>
|
||||||
ref.current && ref.current.ownerDocument ? ref.current.ownerDocument : window;
|
ref.current && ref.current.ownerDocument ? ref.current.ownerDocument : window;
|
||||||
|
|
||||||
const handleScroll = throttleByAnimationFrame(
|
const handleScroll = throttleByAnimationFrame(
|
||||||
(e: React.UIEvent<HTMLElement> | { target: any }) => {
|
(e: React.UIEvent<HTMLElement, UIEvent> | { target: any }) => {
|
||||||
const { visibilityHeight = 400 } = props;
|
|
||||||
const scrollTop = getScroll(e.target, true);
|
const scrollTop = getScroll(e.target, true);
|
||||||
setVisible(scrollTop > visibilityHeight);
|
setVisible(scrollTop >= visibilityHeight);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const bindScrollEvent = () => {
|
const bindScrollEvent = () => {
|
||||||
const { target } = props;
|
|
||||||
const getTarget = target || getDefaultTarget;
|
const getTarget = target || getDefaultTarget;
|
||||||
const container = getTarget();
|
const container = getTarget();
|
||||||
scrollEvent.current = addEventListener(container, 'scroll', (e: React.UIEvent<HTMLElement>) => {
|
scrollEvent.current = addEventListener(container, 'scroll', handleScroll);
|
||||||
handleScroll(e);
|
|
||||||
});
|
|
||||||
handleScroll({ target: container });
|
handleScroll({ target: container });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,26 +62,18 @@ const BackTop: React.FC<BackTopProps> = (props) => {
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
bindScrollEvent();
|
bindScrollEvent();
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollEvent.current) {
|
|
||||||
scrollEvent.current.remove();
|
|
||||||
}
|
|
||||||
handleScroll.cancel();
|
handleScroll.cancel();
|
||||||
|
scrollEvent.current?.remove();
|
||||||
};
|
};
|
||||||
}, [props.target]);
|
}, [target]);
|
||||||
|
|
||||||
const scrollToTop = (e: React.MouseEvent<HTMLDivElement>) => {
|
const scrollToTop = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
const { onClick, target, duration = 450 } = props;
|
scrollTo(0, { getContainer: target || getDefaultTarget, duration });
|
||||||
scrollTo(0, {
|
onClick?.(e);
|
||||||
getContainer: target || getDefaultTarget,
|
|
||||||
duration,
|
|
||||||
});
|
|
||||||
if (typeof onClick === 'function') {
|
|
||||||
onClick(e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
const { getPrefixCls, direction } = React.useContext<ConfigConsumerProps>(ConfigContext);
|
||||||
const { prefixCls: customizePrefixCls, className = '' } = props;
|
|
||||||
const prefixCls = getPrefixCls('back-top', customizePrefixCls);
|
const prefixCls = getPrefixCls('back-top', customizePrefixCls);
|
||||||
const rootPrefixCls = getPrefixCls();
|
const rootPrefixCls = getPrefixCls();
|
||||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||||
@ -128,14 +94,25 @@ const BackTop: React.FC<BackTopProps> = (props) => {
|
|||||||
'children',
|
'children',
|
||||||
'visibilityHeight',
|
'visibilityHeight',
|
||||||
'target',
|
'target',
|
||||||
'visible',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const defaultElement = (
|
||||||
|
<div className={`${prefixCls}-content`}>
|
||||||
|
<div className={`${prefixCls}-icon`}>
|
||||||
|
<VerticalAlignTopOutlined />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<div {...divProps} className={classString} onClick={scrollToTop} ref={ref}>
|
<div {...divProps} className={classString} onClick={scrollToTop} ref={ref}>
|
||||||
<BackTopContent prefixCls={prefixCls} rootPrefixCls={rootPrefixCls} visible={visible}>
|
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
|
||||||
{props.children}
|
{({ className: motionClassName }) =>
|
||||||
</BackTopContent>
|
cloneElement(props.children || defaultElement, ({ className: cloneCls }) => ({
|
||||||
|
className: classNames(motionClassName, cloneCls),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
</CSSMotion>
|
||||||
</div>,
|
</div>,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -144,7 +144,7 @@ describe('ConfigProvider', () => {
|
|||||||
testPair('Avatar', (props) => <Avatar {...props} />);
|
testPair('Avatar', (props) => <Avatar {...props} />);
|
||||||
|
|
||||||
// BackTop
|
// BackTop
|
||||||
testPair('BackTop', (props) => <BackTop visible {...props} />);
|
testPair('BackTop', (props) => <BackTop visibilityHeight={0} {...props} />);
|
||||||
|
|
||||||
// Badge
|
// Badge
|
||||||
testPair('Badge', (props) => {
|
testPair('Badge', (props) => {
|
||||||
|
@ -2,8 +2,7 @@ import VerticalAlignTopOutlined from '@ant-design/icons/VerticalAlignTopOutlined
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import CSSMotion from 'rc-motion';
|
import CSSMotion from 'rc-motion';
|
||||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
import React, { memo, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import React, { memo, useContext, useEffect, useRef } from 'react';
|
|
||||||
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
||||||
import type { ConfigConsumerProps } from '../config-provider';
|
import type { ConfigConsumerProps } from '../config-provider';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
@ -11,7 +10,7 @@ import getScroll from '../_util/getScroll';
|
|||||||
import scrollTo from '../_util/scrollTo';
|
import scrollTo from '../_util/scrollTo';
|
||||||
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
|
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
|
||||||
import FloatButtonGroupContext from './context';
|
import FloatButtonGroupContext from './context';
|
||||||
import type { BackTopProps, FloatButtonShape } from './interface';
|
import type { BackTopProps, FloatButtonProps, FloatButtonShape } from './interface';
|
||||||
import useStyle from './style';
|
import useStyle from './style';
|
||||||
|
|
||||||
const BackTop: React.FC<BackTopProps> = (props) => {
|
const BackTop: React.FC<BackTopProps> = (props) => {
|
||||||
@ -28,46 +27,39 @@ const BackTop: React.FC<BackTopProps> = (props) => {
|
|||||||
...restProps
|
...restProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [visible, setVisible] = useMergedState(false, { value: props.visible });
|
const [visible, setVisible] = useState<boolean>(visibilityHeight === 0);
|
||||||
|
|
||||||
const ref = useRef<HTMLAnchorElement | HTMLButtonElement>(null);
|
const ref = useRef<HTMLAnchorElement | HTMLButtonElement>(null);
|
||||||
|
const scrollEvent = useRef<ReturnType<typeof addEventListener> | null>(null);
|
||||||
const scrollEvent = useRef<any>(null);
|
|
||||||
|
|
||||||
const getDefaultTarget = (): HTMLElement | Document | Window =>
|
const getDefaultTarget = (): HTMLElement | Document | Window =>
|
||||||
ref.current && ref.current.ownerDocument ? ref.current.ownerDocument : window;
|
ref.current && ref.current.ownerDocument ? ref.current.ownerDocument : window;
|
||||||
|
|
||||||
const handleScroll = throttleByAnimationFrame(
|
const handleScroll = throttleByAnimationFrame(
|
||||||
(e: React.UIEvent<HTMLElement> | { target: any }) => {
|
(e: React.UIEvent<HTMLElement, UIEvent> | { target: any }) => {
|
||||||
const scrollTop = getScroll(e.target, true);
|
const scrollTop = getScroll(e.target, true);
|
||||||
setVisible(scrollTop > visibilityHeight!);
|
setVisible(scrollTop >= visibilityHeight);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const bindScrollEvent = () => {
|
const bindScrollEvent = () => {
|
||||||
const getTarget = target || getDefaultTarget;
|
const getTarget = target || getDefaultTarget;
|
||||||
const container = getTarget();
|
const container = getTarget();
|
||||||
scrollEvent.current = addEventListener(container, 'scroll', (e: React.UIEvent<HTMLElement>) => {
|
scrollEvent.current = addEventListener(container, 'scroll', handleScroll);
|
||||||
handleScroll(e);
|
|
||||||
});
|
|
||||||
handleScroll({ target: container });
|
handleScroll({ target: container });
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
bindScrollEvent();
|
bindScrollEvent();
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollEvent.current) {
|
|
||||||
scrollEvent.current.remove();
|
|
||||||
}
|
|
||||||
handleScroll.cancel();
|
handleScroll.cancel();
|
||||||
|
scrollEvent.current?.remove();
|
||||||
};
|
};
|
||||||
}, [target]);
|
}, [target]);
|
||||||
|
|
||||||
const scrollToTop: React.MouseEventHandler<HTMLDivElement> = (e) => {
|
const scrollToTop: React.MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
scrollTo(0, { getContainer: target || getDefaultTarget, duration });
|
scrollTo(0, { getContainer: target || getDefaultTarget, duration });
|
||||||
if (typeof onClick === 'function') {
|
onClick?.(e);
|
||||||
onClick(e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
const { getPrefixCls } = useContext<ConfigConsumerProps>(ConfigContext);
|
||||||
@ -80,7 +72,7 @@ const BackTop: React.FC<BackTopProps> = (props) => {
|
|||||||
|
|
||||||
const mergeShape = groupShape || shape;
|
const mergeShape = groupShape || shape;
|
||||||
|
|
||||||
const contentProps = { prefixCls, icon, type, shape: mergeShape, ...restProps };
|
const contentProps: FloatButtonProps = { prefixCls, icon, type, shape: mergeShape, ...restProps };
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
|
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
|
||||||
|
@ -7,7 +7,7 @@ import BackTop from './BackTop';
|
|||||||
import type { FloatButtonProps, FloatButtonGroupProps } from './interface';
|
import type { FloatButtonProps, FloatButtonGroupProps } from './interface';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
|
|
||||||
export interface PureFloatButtonProps extends FloatButtonProps {
|
export interface PureFloatButtonProps extends Omit<FloatButtonProps, 'target'> {
|
||||||
backTop?: boolean;
|
backTop?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,11 +18,10 @@ export interface PurePanelProps
|
|||||||
items?: PureFloatButtonProps[];
|
items?: PureFloatButtonProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function PureFloatButton({ backTop, ...props }: PureFloatButtonProps) {
|
const PureFloatButton: React.FC<PureFloatButtonProps> = ({ backTop, ...props }) =>
|
||||||
return backTop ? <BackTop {...props} visible target={undefined} /> : <FloatButton {...props} />;
|
backTop ? <BackTop {...props} visibilityHeight={0} /> : <FloatButton {...props} />;
|
||||||
}
|
|
||||||
|
|
||||||
export default function PurePanel({ className, items, ...props }: PurePanelProps) {
|
function PurePanel({ className, items, ...props }: PurePanelProps) {
|
||||||
const { prefixCls: customizePrefixCls } = props;
|
const { prefixCls: customizePrefixCls } = props;
|
||||||
|
|
||||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||||
@ -41,3 +40,5 @@ export default function PurePanel({ className, items, ...props }: PurePanelProps
|
|||||||
|
|
||||||
return <PureFloatButton className={classNames(className, pureCls)} {...props} />;
|
return <PureFloatButton className={classNames(className, pureCls)} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default React.memo(PurePanel);
|
||||||
|
@ -2,52 +2,53 @@ import React from 'react';
|
|||||||
import FloatButton from '..';
|
import FloatButton from '..';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
import { fireEvent, render, sleep } from '../../../tests/utils';
|
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||||
|
|
||||||
const { BackTop } = FloatButton;
|
const { BackTop } = FloatButton;
|
||||||
describe('BackTop', () => {
|
describe('BackTop', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
mountTest(BackTop);
|
mountTest(BackTop);
|
||||||
rtlTest(BackTop);
|
rtlTest(BackTop);
|
||||||
|
|
||||||
it('should scroll to top after click it', async () => {
|
it('should scroll to top after click it', async () => {
|
||||||
const { container } = render(<BackTop visible visibilityHeight={-1} />);
|
const { container } = render(<BackTop />);
|
||||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
||||||
window.scrollY = y;
|
window.scrollY = y;
|
||||||
window.pageYOffset = y;
|
window.pageYOffset = y;
|
||||||
document.documentElement.scrollTop = y;
|
document.documentElement.scrollTop = y;
|
||||||
});
|
});
|
||||||
window.scrollTo(0, 400);
|
window.scrollTo(0, 400);
|
||||||
|
await waitFakeTimer();
|
||||||
expect(document.documentElement.scrollTop).toBe(400);
|
expect(document.documentElement.scrollTop).toBe(400);
|
||||||
fireEvent.click(container.querySelector('.ant-float-btn')!);
|
fireEvent.click(container.querySelector<HTMLButtonElement>('.ant-float-btn')!);
|
||||||
await sleep(500);
|
await waitFakeTimer();
|
||||||
expect(document.documentElement.scrollTop).toBe(0);
|
expect(document.documentElement.scrollTop).toBe(0);
|
||||||
scrollToSpy.mockRestore();
|
scrollToSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('support onClick', () => {
|
it('support onClick', () => {
|
||||||
const onClick = jest.fn();
|
const onClick = jest.fn();
|
||||||
const { container } = render(<BackTop visible visibilityHeight={-1} onClick={onClick} />);
|
const { container } = render(<BackTop onClick={onClick} visibilityHeight={0} />);
|
||||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => {
|
fireEvent.click(container.querySelector<HTMLButtonElement>('.ant-float-btn')!);
|
||||||
window.scrollY = y;
|
|
||||||
window.pageYOffset = y;
|
|
||||||
});
|
|
||||||
document.dispatchEvent(new Event('scroll'));
|
|
||||||
window.scrollTo(0, 400);
|
|
||||||
fireEvent.click(container.querySelector('.ant-float-btn')!);
|
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
scrollToSpy.mockRestore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid target', () => {
|
it('support invalid target', () => {
|
||||||
const onClick = jest.fn();
|
const onClick = jest.fn();
|
||||||
const { container } = render(<BackTop onClick={onClick} visible target={undefined} />);
|
const { container } = render(
|
||||||
fireEvent.click(container.querySelector('.ant-float-btn')!);
|
<BackTop onClick={onClick} visibilityHeight={0} target={undefined} />,
|
||||||
|
);
|
||||||
|
fireEvent.click(container.querySelector<HTMLButtonElement>('.ant-float-btn')!);
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('pass style to float button', () => {
|
it('pass style to float button', () => {
|
||||||
const { container } = render(<BackTop style={{ color: 'red' }} visible target={undefined} />);
|
const { container } = render(<BackTop style={{ color: 'red' }} visibilityHeight={0} />);
|
||||||
const btn = container.querySelector('.ant-float-btn')!;
|
expect(container.querySelector<HTMLButtonElement>('.ant-float-btn')?.style.color).toBe('red');
|
||||||
expect(btn).toHaveAttribute('style', 'color: red;');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,8 +3,8 @@ import FloatButtonGroup from './FloatButtonGroup';
|
|||||||
import BackTop from './BackTop';
|
import BackTop from './BackTop';
|
||||||
import PurePanel from './PurePanel';
|
import PurePanel from './PurePanel';
|
||||||
|
|
||||||
FloatButton.Group = FloatButtonGroup;
|
|
||||||
FloatButton.BackTop = BackTop;
|
FloatButton.BackTop = BackTop;
|
||||||
|
FloatButton.Group = FloatButtonGroup;
|
||||||
FloatButton._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
FloatButton._InternalPanelDoNotUseOrYouWillBeFired = PurePanel;
|
||||||
|
|
||||||
export default FloatButton;
|
export default FloatButton;
|
||||||
|
@ -53,7 +53,6 @@ export interface BackTopProps extends Omit<FloatButtonProps, 'target'> {
|
|||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
visible?: boolean; // Only for test. Don't use it.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CompoundedComponent = React.ForwardRefExoticComponent<
|
export type CompoundedComponent = React.ForwardRefExoticComponent<
|
||||||
|
Loading…
Reference in New Issue
Block a user