fix: Visible change not show Tooltip of Typography (#37147)

* test: Update snapshot

* test: Add test case

* test: fix react 18
This commit is contained in:
二货爱吃白萝卜 2022-08-19 01:31:16 +08:00 committed by GitHub
parent 8010cd19b6
commit 15e4b93e43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 181 additions and 17 deletions

View File

@ -227,6 +227,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
const [expanded, setExpanded] = React.useState(false);
const [isJsEllipsis, setIsJsEllipsis] = React.useState(false);
const [isNativeEllipsis, setIsNativeEllipsis] = React.useState(false);
const [isNativeVisible, setIsNativeVisible] = React.useState(true);
const [enableEllipsis, ellipsisConfig] = useMergedConfig<EllipsisConfig>(ellipsis, {
expandable: false,
});
@ -307,7 +308,31 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
setIsNativeEllipsis(currentEllipsis);
}
}
}, [enableEllipsis, cssEllipsis, children, cssLineClamp]);
}, [enableEllipsis, cssEllipsis, children, cssLineClamp, isNativeVisible]);
// https://github.com/ant-design/ant-design/issues/36786
// Use IntersectionObserver to check if element is invisible
React.useEffect(() => {
const textEle = typographyRef.current;
if (
typeof IntersectionObserver === 'undefined' ||
!textEle ||
!cssEllipsis ||
!mergedEnableEllipsis
) {
return;
}
/* eslint-disable-next-line compat/compat */
const observer = new IntersectionObserver(() => {
setIsNativeVisible(!!textEle.offsetParent);
});
observer.observe(textEle!);
return () => {
observer.disconnect();
};
}, [cssEllipsis, mergedEnableEllipsis]);
// ========================== Tooltip ===========================
let tooltipProps: TooltipProps = {};

View File

@ -618,6 +618,57 @@ Array [
</span>
[After]
</p>,
<div
style="display:none"
>
<span
aria-label="默认display none 样式的超长文字, 悬停tooltip失效了"
class="ant-typography ant-typography-ellipsis ant-typography-single-line"
style="width:100px"
>
默认display none 样式的超长文字, 悬停tooltip失效了
<span
aria-hidden="true"
style="position:fixed;display:block;left:0;top:0;z-index:-9999;visibility:hidden;pointer-events:none;word-break:keep-all;white-space:nowrap"
>
lg
</span>
<span
aria-hidden="true"
style="position:fixed;display:block;left:0;top:0;z-index:-9999;visibility:hidden;pointer-events:none;width:0;white-space:normal;margin:0;padding:0"
>
<span
aria-hidden="true"
>
...
</span>
</span>
</span>
<div>
<div
class="ant-tooltip"
style="opacity:0"
>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-arrow"
>
<span
class="ant-tooltip-arrow-content"
/>
</div>
<div
class="ant-tooltip-inner"
role="tooltip"
>
I am ellipsis now!
</div>
</div>
</div>
</div>
</div>,
]
`;

View File

@ -522,6 +522,33 @@ Array [
</span>
[After]
</p>,
<div
style="display:none"
>
<span
aria-label="默认display none 样式的超长文字, 悬停tooltip失效了"
class="ant-typography ant-typography-ellipsis ant-typography-single-line"
style="width:100px"
>
默认display none 样式的超长文字, 悬停tooltip失效了
<span
aria-hidden="true"
style="position:fixed;display:block;left:0;top:0;z-index:-9999;visibility:hidden;pointer-events:none;word-break:keep-all;white-space:nowrap"
>
lg
</span>
<span
aria-hidden="true"
style="position:fixed;display:block;left:0;top:0;z-index:-9999;visibility:hidden;pointer-events:none;width:0;white-space:normal;margin:0;padding:0"
>
<span
aria-hidden="true"
>
...
</span>
</span>
</span>
</div>,
]
`;

View File

@ -1,5 +1,6 @@
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { fireEvent, render, sleep, triggerResize, waitFor } from '../../../tests/utils';
import Base from '../Base';
// eslint-disable-next-line no-unused-vars
@ -14,6 +15,7 @@ describe('Typography.Ellipsis', () => {
const LINE_STR_COUNT = 20;
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
let mockRectSpy;
let getWidthTimes = 0;
beforeAll(() => {
mockRectSpy = spyElementPrototypes(HTMLElement, {
@ -26,7 +28,10 @@ describe('Typography.Ellipsis', () => {
},
},
offsetWidth: {
get: () => 100,
get: () => {
getWidthTimes += 1;
return 100;
},
},
getBoundingClientRect() {
let html = this.innerHTML;
@ -39,6 +44,7 @@ describe('Typography.Ellipsis', () => {
afterEach(() => {
errorSpy.mockReset();
getWidthTimes = 0;
});
afterAll(() => {
@ -223,28 +229,70 @@ describe('Typography.Ellipsis', () => {
it('should have custom expand style', async () => {
const symbol = 'more';
const { container: wrapper } = render(
const { container } = render(
<Base ellipsis={{ expandable: true, symbol }} component="p">
{fullStr}
</Base>,
);
expect(wrapper.querySelector('.ant-typography-expand').textContent).toEqual('more');
expect(container.querySelector('.ant-typography-expand').textContent).toEqual('more');
});
it('can use css ellipsis', () => {
const { container: wrapper } = render(<Base ellipsis component="p" />);
expect(wrapper.querySelectorAll('.ant-typography-ellipsis-single-line').length).toBeGreaterThan(
0,
);
});
describe('native css ellipsis', () => {
it('can use css ellipsis', () => {
const { container } = render(<Base ellipsis component="p" />);
expect(container.querySelector('.ant-typography-ellipsis-single-line')).toBeTruthy();
});
it('should calculate padding', () => {
const { container: wrapper } = render(
<Base ellipsis component="p" style={{ paddingTop: '12px', paddingBottom: '12px' }} />,
);
expect(wrapper.querySelectorAll('.ant-typography-ellipsis-single-line').length).toBeGreaterThan(
0,
);
// https://github.com/ant-design/ant-design/issues/36786
it('Tooltip should recheck on parent visible change', () => {
const originIntersectionObserver = global.IntersectionObserver;
let elementChangeCallback;
const observeFn = jest.fn();
const disconnectFn = jest.fn();
global.IntersectionObserver = class MockIntersectionObserver {
constructor(callback) {
elementChangeCallback = callback;
}
observe = observeFn;
disconnect = disconnectFn;
};
const { container, unmount } = render(<Base ellipsis component="p" />);
expect(observeFn).toHaveBeenCalled();
// Hide first
act(() => {
elementChangeCallback();
});
// Trigger visible should trigger recheck
getWidthTimes = 0;
Object.defineProperty(container.querySelector('.ant-typography'), 'offsetParent', {
get: () => document.body,
});
act(() => {
elementChangeCallback();
});
expect(getWidthTimes).toBeGreaterThan(0);
unmount();
expect(disconnectFn).toHaveBeenCalled();
global.IntersectionObserver = originIntersectionObserver;
});
it('should calculate padding', () => {
const { container } = render(
<Base ellipsis component="p" style={{ paddingTop: '12px', paddingBottom: '12px' }} />,
);
expect(container.querySelector('.ant-typography-ellipsis-single-line')).toBeTruthy();
});
});
describe('should tooltip support', () => {

View File

@ -26,6 +26,13 @@ const App: React.FC = () => {
const [copyable, setCopyable] = useState(false);
const [editable, setEditable] = useState(false);
const [expandable, setExpandable] = useState(false);
const [display, setDisplay] = useState('none');
React.useEffect(() => {
setTimeout(() => {
setDisplay('block');
}, 100);
}, []);
return (
<>
@ -60,6 +67,12 @@ const App: React.FC = () => {
<p>
[Before]<Text ellipsis>not ellipsis</Text>[After]
</p>
<div style={{ display }}>
<Text style={{ width: 100 }} ellipsis={{ tooltip: 'I am ellipsis now!' }}>
默认display none 样式的超长文字, 悬停tooltip失效了
</Text>
</div>
</>
);
};