name | -type | -default | -description | -
---|---|---|---|
overlayClassName | -string | -- | additional className added to popup overlay | -
trigger | -string | string[] | -['hover'] | -which actions cause tooltip shown. enum of 'hover','click','focus' | -
mouseEnterDelay | -number | -0 | -delay time to show when mouse enter.unit: s. | -
mouseLeaveDelay | -number | -0.1 | -delay time to hide when mouse leave.unit: s. | -
overlayStyle | -Object | -- | additional style of overlay node | -
prefixCls | -String | -rc-tooltip | -prefix class name | -
transitionName | -String|Object | -- | same as https://github.com/react-component/animate | -
onVisibleChange | -Function | -- | call when visible is changed | -
afterVisibleChange | -Function | -- | call after visible is changed | -
visible | -boolean | -- | whether tooltip is visible | -
defaultVisible | -boolean | -- | whether tooltip is visible initially | -
placement | -String | -- | one of ['left','right','top','bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'] | -
align | -Object: alignConfig of [dom-align](https://github.com/yiminghe/dom-align) | -- | value will be merged into placement's config | -
onPopupAlign | -function(popupDomNode, align) | -- | callback when popup node is aligned | -
overlay | -React.Element | () => React.Element | -- | popup content | -
overlayInnerStyle | -Object | -- | set overlay inner style | -
arrowContent | -React.Node | -null | -arrow content | -
getTooltipContainer | -function | -- | Function returning html node which will act as tooltip container. By default the tooltip attaches to the body. If you want to change the container, simply return a new element. | -
destroyTooltipOnHide | -boolean | { keepParent: boolean } | -false | -whether destroy tooltip when tooltip is hidden.In general, destroyTooltipOnHide will only remove itself instead of parent container of it.Parent container will be removed include tooltip when keepParent is true | -
id | -String | -- | Id which gets attached to the tooltip content. Can be used with aria-describedby to achieve Screenreader-Support. | -
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/demo/formError.md b/docs/demo/formError.md
index 51a3480..e3bf2e8 100644
--- a/docs/demo/formError.md
+++ b/docs/demo/formError.md
@@ -1,3 +1,8 @@
-## formError
+---
+title: formError
+nav:
+ title: Demo
+ path: /demo
+---
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/demo/onVisibleChange.md b/docs/demo/onVisibleChange.md
index 989b373..4f30b05 100644
--- a/docs/demo/onVisibleChange.md
+++ b/docs/demo/onVisibleChange.md
@@ -1,3 +1,8 @@
-## onVisibleChange
+---
+title: onVisibleChange
+nav:
+ title: Demo
+ path: /demo
+---
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/demo/placement.md b/docs/demo/placement.md
index e295293..192ec92 100644
--- a/docs/demo/placement.md
+++ b/docs/demo/placement.md
@@ -1,3 +1,8 @@
-## placement
+---
+title: placement
+nav:
+ title: Demo
+ path: /demo
+---
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/demo/point.md b/docs/demo/point.md
new file mode 100644
index 0000000..073a89b
--- /dev/null
+++ b/docs/demo/point.md
@@ -0,0 +1,8 @@
+---
+title: Point
+nav:
+ title: Demo
+ path: /demo
+---
+
+
\ No newline at end of file
diff --git a/docs/demo/showArrow.md b/docs/demo/showArrow.md
new file mode 100644
index 0000000..7925fe5
--- /dev/null
+++ b/docs/demo/showArrow.md
@@ -0,0 +1,8 @@
+---
+title: showArrow
+nav:
+ title: Demo
+ path: /demo
+---
+
+
diff --git a/docs/demo/simple.md b/docs/demo/simple.md
index 51d9e8f..23f3e34 100644
--- a/docs/demo/simple.md
+++ b/docs/demo/simple.md
@@ -1,3 +1,8 @@
-## simple
+---
+title: simple
+nav:
+ title: Demo
+ path: /demo
+---
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/examples/placement.tsx b/docs/examples/placement.tsx
index 40c6188..987141a 100644
--- a/docs/examples/placement.tsx
+++ b/docs/examples/placement.tsx
@@ -1,9 +1,10 @@
import React from 'react';
import Tooltip from 'rc-tooltip';
import '../../assets/bootstrap.less';
+import Popup from '../../src/Popup';
const text = Tooltip Text;
-const styles = {
+const styles: React.CSSProperties = {
display: 'table-cell',
height: '60px',
width: '80px',
@@ -18,74 +19,87 @@ const rowStyle = {
};
const Test = () => (
-
-
-
-
- Left
-
-
-
-
- Top
-
-
-
-
- Bottom
-
-
-
-
- Right
-
-
+ <>
+
+
+
+
-
-
-
- Left Top
-
-
-
-
- Left Bottom
-
-
-
-
- Right Top
-
-
-
-
- Right Bottom
-
-
+
+
+ Debug Usage
+
+ Test
+
-
-
+ >
);
export default Test;
diff --git a/docs/examples/point.tsx b/docs/examples/point.tsx
new file mode 100644
index 0000000..d59ce6a
--- /dev/null
+++ b/docs/examples/point.tsx
@@ -0,0 +1,56 @@
+import Tooltip from 'rc-tooltip';
+import React from 'react';
+import '../../assets/bootstrap_white.less';
+
+const text = Tooltip Text;
+
+const Test = () => {
+ const scrollRef = React.useRef();
+
+ return (
+
+
+
+ }
+ >
+
+ Hover Me
+
+
+
+
+
+ );
+};
+
+export default Test;
diff --git a/docs/examples/showArrow.tsx b/docs/examples/showArrow.tsx
new file mode 100644
index 0000000..882f6bf
--- /dev/null
+++ b/docs/examples/showArrow.tsx
@@ -0,0 +1,91 @@
+import React from 'react';
+import Tooltip from 'rc-tooltip';
+import '../../assets/bootstrap_white.less';
+
+const text = Tooltip Text;
+const styles = {
+ display: 'table-cell',
+ height: '60px',
+ width: '80px',
+ textAlign: 'center',
+ background: '#f6f6f6',
+ verticalAlign: 'middle',
+ border: '5px solid white',
+};
+
+const rowStyle = {
+ display: 'table-row',
+};
+
+const Test = () => (
+
+
+
+
+
+);
+
+export default Test;
diff --git a/docs/index.md b/docs/index.md
index 53a98a3..4c79a7b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,5 +1,8 @@
---
-title: rc-tooltip
+hero:
+ title: rc-tooltip
+ description: React Tooltip
---
+
diff --git a/package.json b/package.json
index 0e99715..454c6d0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rc-tooltip",
- "version": "5.1.1",
+ "version": "6.1.2",
"description": "React Tooltip",
"keywords": [
"react",
@@ -17,53 +17,52 @@
"url": "git@github.com:react-component/tooltip.git"
},
"license": "MIT",
+ "maintainers": [
+ "yiminghe@gmail.com"
+ ],
+ "main": "lib/index",
+ "module": "es/index",
"files": [
- "dist",
"lib",
"es",
"assets/*.css",
"assets/*.less"
],
- "main": "lib/index",
- "module": "es/index",
"scripts": {
- "start": "dumi dev",
- "docs:build": "dumi build",
- "docs:deploy": "gh-pages -d .doc",
"compile": "father build && lessc assets/bootstrap.less assets/bootstrap.css && lessc assets/bootstrap_white.less assets/bootstrap_white.css",
- "coverage": "father test --coverage",
+ "prepare": "dumi setup",
+ "docs:build": "dumi build",
+ "docs:deploy": "gh-pages -d dist",
"lint": "eslint src/ --ext .tsx,.ts,.jsx,.js",
- "now-build": "npm run build",
"prepublishOnly": "npm run compile && np --no-cleanup --yolo --no-publish",
- "test": "father test"
+ "postpublish": "npm run docs:build && npm run docs:deploy",
+ "start": "dumi dev",
+ "test": "rc-test"
},
"dependencies": {
"@babel/runtime": "^7.11.2",
- "rc-trigger": "^5.0.0"
+ "@rc-component/trigger": "^1.18.0",
+ "classnames": "^2.3.1"
},
"devDependencies": {
- "@types/jest": "^26.0.0",
- "@types/react": "^16.9.9",
- "@types/react-dom": "^17.0.9",
+ "@rc-component/father-plugin": "^1.0.0",
+ "@testing-library/react": "^13.4.0",
+ "@types/jest": "^29.4.0",
+ "@types/react": "^18.0.26",
+ "@types/react-dom": "^18.0.10",
"@types/warning": "^3.0.0",
"cross-env": "^7.0.0",
- "dumi": "^1.1.0",
- "enzyme": "^3.10.0",
- "enzyme-adapter-react-16": "^1.15.1",
- "enzyme-to-json": "^3.4.3",
+ "dumi": "^2.2.13",
"eslint": "^7.1.0",
- "father": "^2.23.1",
- "father-build": "^1.18.6",
+ "father": "^4.0.0",
"gh-pages": "^3.1.0",
- "less": "^3.11.1",
+ "less": "^4.1.1",
"np": "^7.1.0",
- "react": "^16.10.2",
- "react-dom": "^16.10.2",
+ "rc-test": "^7.0.9",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
"typescript": "^4.0.5"
},
- "maintainers": [
- "yiminghe@gmail.com"
- ],
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
diff --git a/src/Content.tsx b/src/Content.tsx
deleted file mode 100644
index b91f173..0000000
--- a/src/Content.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import * as React from 'react';
-
-export interface ContentProps {
- prefixCls?: string;
- overlay: (() => React.ReactNode) | React.ReactNode;
- id: string;
- overlayInnerStyle?: React.CSSProperties;
-}
-
-const Content = (props: ContentProps) => {
- const { overlay, prefixCls, id, overlayInnerStyle } = props;
-
- return (
-
- {typeof overlay === 'function' ? overlay() : overlay}
-
- );
-};
-
-export default Content;
diff --git a/src/Popup.tsx b/src/Popup.tsx
new file mode 100644
index 0000000..cbaa9cf
--- /dev/null
+++ b/src/Popup.tsx
@@ -0,0 +1,23 @@
+import classNames from 'classnames';
+import * as React from 'react';
+
+export interface ContentProps {
+ prefixCls?: string;
+ children: (() => React.ReactNode) | React.ReactNode;
+ id?: string;
+ overlayInnerStyle?: React.CSSProperties;
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+export default function Popup(props: ContentProps) {
+ const { children, prefixCls, id, overlayInnerStyle, className, style } = props;
+
+ return (
+
+
+ {typeof children === 'function' ? children() : children}
+
+
+ );
+}
diff --git a/src/Tooltip.tsx b/src/Tooltip.tsx
index 4948c32..944f711 100644
--- a/src/Tooltip.tsx
+++ b/src/Tooltip.tsx
@@ -1,12 +1,22 @@
+import type { ArrowType, TriggerProps, TriggerRef } from '@rc-component/trigger';
+import Trigger from '@rc-component/trigger';
+import type { ActionType, AlignType, AnimationType } from '@rc-component/trigger/lib/interface';
import * as React from 'react';
-import { useRef, useImperativeHandle, forwardRef } from 'react';
-import Trigger from 'rc-trigger';
-import type { TriggerProps } from 'rc-trigger';
-import type { AlignType, AnimationType, ActionType } from 'rc-trigger/lib/interface';
+import { forwardRef, useImperativeHandle, useRef } from 'react';
import { placements } from './placements';
-import Content from './Content';
+import Popup from './Popup';
-export interface TooltipProps extends Pick {
+export interface TooltipProps
+ extends Pick<
+ TriggerProps,
+ | 'onPopupAlign'
+ | 'builtinPlacements'
+ | 'fresh'
+ | 'children'
+ | 'mouseLeaveDelay'
+ | 'mouseEnterDelay'
+ | 'prefixCls'
+ > {
trigger?: ActionType | ActionType[];
defaultVisible?: boolean;
visible?: boolean;
@@ -22,25 +32,22 @@ export interface TooltipProps extends Pick React.ReactNode) | React.ReactNode;
overlayStyle?: React.CSSProperties;
overlayClassName?: string;
- prefixCls?: string;
- mouseEnterDelay?: number;
- mouseLeaveDelay?: number;
getTooltipContainer?: (node: HTMLElement) => HTMLElement;
- destroyTooltipOnHide?:
- | boolean
- | {
- keepParent?: boolean;
- };
+ destroyTooltipOnHide?: boolean;
align?: AlignType;
+ showArrow?: boolean | ArrowType;
arrowContent?: React.ReactNode;
id?: string;
- children?: React.ReactElement;
- popupVisible?: boolean;
overlayInnerStyle?: React.CSSProperties;
zIndex?: number;
}
-const Tooltip = (props: TooltipProps, ref) => {
+export interface TooltipRef {
+ nativeElement: HTMLElement;
+ forceAlign: VoidFunction;
+}
+
+const Tooltip = (props: TooltipProps, ref: React.Ref) => {
const {
overlayClassName,
trigger = ['hover'],
@@ -60,42 +67,26 @@ const Tooltip = (props: TooltipProps, ref) => {
defaultVisible,
getTooltipContainer,
overlayInnerStyle,
+ arrowContent,
+ overlay,
+ id,
+ showArrow = true,
...restProps
} = props;
- const domRef = useRef(null);
- useImperativeHandle(ref, () => domRef.current);
+ const triggerRef = useRef(null);
+ useImperativeHandle(ref, () => triggerRef.current);
- const extraProps = { ...restProps };
+ const extraProps: Partial = { ...restProps };
if ('visible' in props) {
extraProps.popupVisible = props.visible;
}
- const getPopupElement = () => {
- const { arrowContent = null, overlay, id } = props;
- return [
-
- {arrowContent}
- ,
- ,
- ];
- };
-
- let destroyTooltip = false;
- let autoDestroy = false;
- if (typeof destroyTooltipOnHide === 'boolean') {
- destroyTooltip = destroyTooltipOnHide;
- } else if (destroyTooltipOnHide && typeof destroyTooltipOnHide === 'object') {
- const { keepParent } = destroyTooltipOnHide;
- destroyTooltip = keepParent === true;
- autoDestroy = keepParent === false;
- }
+ const getPopupElement = () => (
+
+ {overlay}
+
+ );
return (
{
action={trigger}
builtinPlacements={placements}
popupPlacement={placement}
- ref={domRef}
+ ref={triggerRef}
popupAlign={align}
getPopupContainer={getTooltipContainer}
onPopupVisibleChange={onVisibleChange}
@@ -114,11 +105,11 @@ const Tooltip = (props: TooltipProps, ref) => {
popupAnimation={animation}
popupMotion={motion}
defaultPopupVisible={defaultVisible}
- destroyPopupOnHide={destroyTooltip}
- autoDestroy={autoDestroy}
+ autoDestroy={destroyTooltipOnHide}
mouseLeaveDelay={mouseLeaveDelay}
popupStyle={overlayStyle}
mouseEnterDelay={mouseEnterDelay}
+ arrow={showArrow}
{...extraProps}
>
{children}
diff --git a/src/index.tsx b/src/index.tsx
index d8851cb..6da28f5 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,3 +1,7 @@
+import Popup from './Popup';
import Tooltip from './Tooltip';
+export type { TooltipRef } from './Tooltip';
+export { Popup };
+
export default Tooltip;
diff --git a/src/placements.tsx b/src/placements.tsx
index 789dce3..6371e88 100644
--- a/src/placements.tsx
+++ b/src/placements.tsx
@@ -1,82 +1,84 @@
-import { BuildInPlacements } from 'rc-trigger';
+import type { BuildInPlacements } from '@rc-component/trigger';
-const autoAdjustOverflow = {
- adjustX: 1,
+const autoAdjustOverflowTopBottom = {
+ shiftX: 64,
adjustY: 1,
};
+const autoAdjustOverflowLeftRight = { adjustX: 1, shiftY: true };
+
const targetOffset = [0, 0];
export const placements: BuildInPlacements = {
left: {
points: ['cr', 'cl'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowLeftRight,
offset: [-4, 0],
targetOffset,
},
right: {
points: ['cl', 'cr'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowLeftRight,
offset: [4, 0],
targetOffset,
},
top: {
points: ['bc', 'tc'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowTopBottom,
offset: [0, -4],
targetOffset,
},
bottom: {
points: ['tc', 'bc'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowTopBottom,
offset: [0, 4],
targetOffset,
},
topLeft: {
points: ['bl', 'tl'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowTopBottom,
offset: [0, -4],
targetOffset,
},
leftTop: {
points: ['tr', 'tl'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowLeftRight,
offset: [-4, 0],
targetOffset,
},
topRight: {
points: ['br', 'tr'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowTopBottom,
offset: [0, -4],
targetOffset,
},
rightTop: {
points: ['tl', 'tr'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowLeftRight,
offset: [4, 0],
targetOffset,
},
bottomRight: {
points: ['tr', 'br'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowTopBottom,
offset: [0, 4],
targetOffset,
},
rightBottom: {
points: ['bl', 'br'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowLeftRight,
offset: [4, 0],
targetOffset,
},
bottomLeft: {
points: ['tl', 'bl'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowTopBottom,
offset: [0, 4],
targetOffset,
},
leftBottom: {
points: ['br', 'bl'],
- overflow: autoAdjustOverflow,
+ overflow: autoAdjustOverflowLeftRight,
offset: [-4, 0],
targetOffset,
},
diff --git a/tests/__mocks__/@rc-component/trigger.js b/tests/__mocks__/@rc-component/trigger.js
new file mode 100644
index 0000000..887c966
--- /dev/null
+++ b/tests/__mocks__/@rc-component/trigger.js
@@ -0,0 +1,3 @@
+import Trigger from '@rc-component/trigger/lib/mock';
+
+export default Trigger;
diff --git a/tests/__mocks__/rc-trigger.js b/tests/__mocks__/rc-trigger.js
deleted file mode 100644
index 3230307..0000000
--- a/tests/__mocks__/rc-trigger.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import Trigger from 'rc-trigger/lib/mock';
-
-export default Trigger;
diff --git a/tests/index.test.js b/tests/index.test.js
deleted file mode 100644
index 30e2ebc..0000000
--- a/tests/index.test.js
+++ /dev/null
@@ -1,173 +0,0 @@
-import React from 'react';
-import { mount } from 'enzyme';
-import Tooltip from '../src';
-
-const verifyContent = (wrapper, content) => {
- expect(wrapper.find('.x-content').text()).toBe(content);
- expect(wrapper.find('Trigger').instance().getPopupDomNode()).toBeTruthy();
- wrapper.find('.target').simulate('click');
- expect(wrapper.find('.rc-tooltip').hostNodes().hasClass('rc-tooltip-hidden')).toBe(true);
-};
-
-describe('rc-tooltip', () => {
- window.requestAnimationFrame = window.setTimeout;
- window.cancelAnimationFrame = window.clearTimeout;
-
- describe('shows and hides itself on click', () => {
- it('using an element overlay', () => {
- const wrapper = mount(
- Tooltip content}
- >
- Click this
- ,
- );
- wrapper.find('.target').simulate('click');
- verifyContent(wrapper, 'Tooltip content');
- });
-
- it('using a function overlay', () => {
- const wrapper = mount(
- Tooltip content}
- >
- Click this
- ,
- );
- wrapper.find('.target').simulate('click');
- verifyContent(wrapper, 'Tooltip content');
- });
-
- // https://github.com/ant-design/ant-design/pull/23155
- it('using style inner style', () => {
- const wrapper = mount(
- Tooltip content}
- overlayInnerStyle={{ background: 'red' }}
- >
- Click this
- ,
- );
- wrapper.find('.target').simulate('click');
- expect(wrapper.find('.rc-tooltip-inner').props().style).toEqual({ background: 'red' });
- });
-
- it('access of ref', () => {
- const domRef = React.createRef();
- mount(
- Tooltip content}
- ref={domRef}
- >
- Click this
- ,
- );
- expect(domRef.current).toBeTruthy();
- });
- });
- describe('destroyTooltipOnHide', () => {
- const destroyVerifyContent = (wrapper, content) => {
- wrapper.find('.target').simulate('click');
- expect(wrapper.find('.x-content').text()).toBe(content);
- expect(wrapper.find('Trigger').instance().getPopupDomNode()).toBeTruthy();
- wrapper.find('.target').simulate('click');
- };
- it('default value', () => {
- const wrapper = mount(
- Tooltip content}
- >
- Click this
- ,
- );
- wrapper.find('.target').simulate('click');
- verifyContent(wrapper, 'Tooltip content');
- });
- it('should only remove tooltip when value is true', () => {
- const wrapper = mount(
- Tooltip content}
- >
- Click this
- ,
- );
- destroyVerifyContent(wrapper, 'Tooltip content');
- expect(wrapper.html()).toBe('Click this');
- });
- it('should only remove tooltip when keepParent is true', () => {
- const wrapper = mount(
- Tooltip content}
- >
- Click this
- ,
- );
- destroyVerifyContent(wrapper, 'Tooltip content');
- expect(wrapper.html()).toBe('Click this');
- });
- it('should remove tooltip and container when keepParent is false', () => {
- const wrapper = mount(
- Tooltip content}
- >
- Click this
- ,
- );
- destroyVerifyContent(wrapper, 'Tooltip content');
- expect(wrapper.html()).toBe('Click this');
- });
- });
-
- // This is only test for motion pass to internal rc-trigger
- // It's safe to remove since meaningless to rc-tooltip if refactor
- it('should motion props work', () => {
- const wrapper = mount(
-
- Bamboo
- ,
- );
-
- expect(wrapper.find('Trigger').props().popupMotion).toEqual({ motionName: 'bamboo-is-light' });
- });
-
- it('zIndex', () => {
- jest.useFakeTimers();
-
- const wrapper = mount(
-
- Light
- ,
- );
- wrapper.find('.target').simulate('click');
-
- jest.runAllTimers();
- wrapper.update();
-
- expect(wrapper.find('div.rc-tooltip').prop('style')).toEqual(
- expect.objectContaining({
- zIndex: 903,
- }),
- );
-
- jest.useRealTimers();
- });
-});
diff --git a/tests/index.test.tsx b/tests/index.test.tsx
new file mode 100644
index 0000000..d167d0c
--- /dev/null
+++ b/tests/index.test.tsx
@@ -0,0 +1,254 @@
+import { act, fireEvent, render } from '@testing-library/react';
+import React from 'react';
+import Tooltip, { TooltipRef } from '../src';
+
+const verifyContent = (wrapper: HTMLElement, content: string) => {
+ expect(wrapper.querySelector('.x-content').textContent).toBe(content);
+ fireEvent.click(wrapper.querySelector('.target'));
+ expect(wrapper.querySelector('.rc-tooltip').classList.contains('rc-tooltip-hidden')).toBe(true);
+};
+
+describe('rc-tooltip', () => {
+ window.requestAnimationFrame = window.setTimeout;
+ window.cancelAnimationFrame = window.clearTimeout;
+ beforeEach(() => {
+ jest.useFakeTimers();
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
+ });
+
+ async function waitFakeTimers() {
+ for (let i = 0; i < 100; i += 1) {
+ await act(async () => {
+ jest.advanceTimersByTime(100);
+ await Promise.resolve();
+ });
+ }
+ }
+
+ describe('shows and hides itself on click', () => {
+ it('using an element overlay', () => {
+ const { container } = render(
+ Tooltip content}
+ >
+ Click this
+ ,
+ );
+
+ fireEvent.click(container.querySelector('.target'));
+
+ verifyContent(container, 'Tooltip content');
+ });
+
+ it('using a function overlay', () => {
+ const { container } = render(
+ Tooltip content}
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ verifyContent(container, 'Tooltip content');
+ });
+
+ // https://github.com/ant-design/ant-design/pull/23155
+ it('using style inner style', () => {
+ const { container } = render(
+ Tooltip content}
+ overlayInnerStyle={{ background: 'red' }}
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ expect(
+ (container.querySelector('.rc-tooltip-inner') as HTMLElement).style.background,
+ ).toEqual('red');
+ });
+
+ it('access of ref', () => {
+ const domRef = React.createRef();
+ render(
+ Tooltip content}
+ ref={domRef}
+ >
+ Click this
+ ,
+ );
+ expect(domRef.current).toBeTruthy();
+ });
+ });
+
+ describe('destroyTooltipOnHide', () => {
+ const destroyVerifyContent = async (wrapper: HTMLElement, content: string) => {
+ fireEvent.click(wrapper.querySelector('.target'));
+ await waitFakeTimers();
+
+ expect(wrapper.querySelector('.x-content').textContent).toBe(content);
+
+ fireEvent.click(wrapper.querySelector('.target'));
+ await waitFakeTimers();
+ };
+ it('default value', () => {
+ const { container } = render(
+ Tooltip content}
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ verifyContent(container, 'Tooltip content');
+ });
+
+ it('should only remove tooltip when value is true', async () => {
+ const { container } = render(
+ Tooltip content}
+ >
+ Click this
+ ,
+ );
+ await destroyVerifyContent(container, 'Tooltip content');
+ expect(document.querySelector('.x-content')).toBeFalsy();
+ });
+ });
+
+ it('zIndex', () => {
+ jest.useFakeTimers();
+
+ const { container } = render(
+
+ Light
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+
+ jest.runAllTimers();
+
+ expect((container.querySelector('div.rc-tooltip') as HTMLElement).style.zIndex).toBe('903');
+
+ jest.useRealTimers();
+ });
+
+ describe('showArrow', () => {
+ it('should show tooltip arrow default', () => {
+ const { container } = render(
+ Tooltip content}
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ expect(container.querySelector('.rc-tooltip-arrow')).toBeTruthy();
+ });
+ it('should show tooltip arrow when showArrow is true', () => {
+ const { container } = render(
+ Tooltip content}
+ showArrow
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ expect(container.querySelector('.rc-tooltip-arrow')).toBeTruthy();
+ });
+ it('should show tooltip arrow when showArrow is object', () => {
+ const { container } = render(
+ Tooltip content}
+ showArrow={{
+ className: 'abc',
+ }}
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ expect(container.querySelector('.rc-tooltip-arrow')).toBeTruthy();
+ expect(container.querySelector('.rc-tooltip-arrow').classList.contains('abc')).toBeTruthy();
+ });
+ it('should hide tooltip arrow when showArrow is false', () => {
+ const { container } = render(
+ Tooltip content}
+ showArrow={false}
+ >
+ Click this
+ ,
+ );
+ fireEvent.click(container.querySelector('.target'));
+ expect(container.querySelector('.rc-tooltip').classList).not.toContain(
+ 'rc-tooltip-show-arrow',
+ );
+ expect(container.querySelector('.rc-tooltip-arrow')).toBeFalsy();
+ });
+ });
+
+ it('visible', () => {
+ const App = () => {
+ const [open, setOpen] = React.useState(false);
+ return (
+ Tooltip content} visible={open}>
+ {
+ setOpen(true);
+ }}
+ />
+
+ );
+ };
+ const { container } = render( );
+
+ expect(container.querySelector('.x-content')).toBeFalsy();
+
+ fireEvent.click(container.querySelector('.target'));
+ expect(container.querySelector('.x-content')).toBeTruthy();
+ });
+
+ it('ref support nativeElement', () => {
+ const nodeRef = React.createRef();
+
+ const { container } = render(
+ }>
+
+ ,
+ );
+
+ expect(nodeRef.current.nativeElement).toBe(container.querySelector('button'));
+ });
+});
diff --git a/tests/popup.test.tsx b/tests/popup.test.tsx
new file mode 100644
index 0000000..dce44ee
--- /dev/null
+++ b/tests/popup.test.tsx
@@ -0,0 +1,8 @@
+import { Popup } from '../src';
+
+describe('Popup', () => {
+ // Used in antd for C2D2C
+ it('should export', () => {
+ expect(Popup).toBeTruthy();
+ });
+});
diff --git a/tests/setup.js b/tests/setup.js
index 684b8a6..8623ee6 100644
--- a/tests/setup.js
+++ b/tests/setup.js
@@ -1,8 +1,38 @@
-global.requestAnimationFrame = global.requestAnimationFrame || function requestAnimationFrame(cb) {
- return setTimeout(cb, 0);
-};
+const React = require('react');
+const util = require('util');
-const Enzyme = require('enzyme');
-const Adapter = require('enzyme-adapter-react-16');
+// eslint-disable-next-line no-console
+console.log('Current React Version:', React.version);
-Enzyme.configure({ adapter: new Adapter() });
+/* eslint-disable global-require */
+if (typeof window !== 'undefined') {
+ global.window.resizeTo = (width, height) => {
+ global.window.innerWidth = width || global.window.innerWidth;
+ global.window.innerHeight = height || global.window.innerHeight;
+ global.window.dispatchEvent(new Event('resize'));
+ };
+ global.window.scrollTo = () => {};
+ // ref: https://github.com/ant-design/ant-design/issues/18774
+ if (!window.matchMedia) {
+ Object.defineProperty(global.window, 'matchMedia', {
+ writable: true,
+ configurable: true,
+ value: jest.fn((query) => ({
+ matches: query.includes('max-width'),
+ addListener: jest.fn(),
+ removeListener: jest.fn(),
+ })),
+ });
+ }
+
+ // Fix css-animation or rc-motion deps on these
+ // https://github.com/react-component/motion/blob/9c04ef1a210a4f3246c9becba6e33ea945e00669/src/util/motion.ts#L27-L35
+ // https://github.com/yiminghe/css-animation/blob/a5986d73fd7dfce75665337f39b91483d63a4c8c/src/Event.js#L44
+ window.AnimationEvent = window.AnimationEvent || window.Event;
+ window.TransitionEvent = window.TransitionEvent || window.Event;
+
+ // ref: https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
+ // ref: https://github.com/jsdom/jsdom/issues/2524
+ Object.defineProperty(window, 'TextEncoder', { writable: true, value: util.TextEncoder });
+ Object.defineProperty(window, 'TextDecoder', { writable: true, value: util.TextDecoder });
+}
diff --git a/tsconfig.json b/tsconfig.json
index e23fb37..33bd1ce 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,14 +3,27 @@
"target": "esnext",
"moduleResolution": "node",
"baseUrl": "./",
- "jsx": "preserve",
+ "jsx": "react",
"declaration": true,
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
- "@/*": ["src/*"],
- "@@/*": ["src/.umi/*"],
- "rc-tooltip": ["src/index.tsx"]
+ "@/*": [
+ "src/*"
+ ],
+ "@@/*": [
+ ".dumi/tmp/*"
+ ],
+ "rc-tooltip": [
+ "src/index.tsx"
+ ]
}
- }
-}
+ },
+ "include": [
+ ".dumirc.ts",
+ "./src/**/*.ts",
+ "./src/**/*.tsx",
+ "./docs/**/*.tsx",
+ "./tests/**/*.tsx"
+ ]
+}
\ No newline at end of file