MM-62005 Remove FloatingFocusManager from PluginLinkTooltip (#30663)

* MM-62005 Remove FloatingFocusManager from PluginLinkTooltip

* Update tests to define more realistic plugin components

* Revert "Update tests to define more realistic plugin components"

This reverts commit c23307112c2bc5091b931980885cc79e4b945ff8.

* Revert changes to DeepPartial

* Use class component for test component
Этот коммит содержится в:
Harrison Healey
2025-04-14 14:18:26 -04:00
коммит произвёл GitHub
родитель 6f33b721de
Коммит 964678fc45
2 изменённых файлов: 148 добавлений и 16 удалений

Просмотреть файл

@@ -0,0 +1,135 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {act, renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {RootHtmlPortalId} from 'utils/constants';
import PluginLinkTooltip from '.';
class TestLinkTooltip extends React.PureComponent<{href: string}> {
render() {
if (this.props.href.includes('tooltip')) {
return <div>{'This is a link tooltip'}</div>;
}
return null;
}
}
describe('PluginLinkTooltip', () => {
const baseState = {
plugins: {
components: {
LinkTooltip: [
{
id: 'test',
pluginId: 'example.test',
component: TestLinkTooltip,
},
],
},
},
};
test('should show tooltip on hover', async () => {
renderWithContext(
<>
<PluginLinkTooltip
nodeAttributes={{
href: 'https://example.com/tooltip',
}}
>
{'This is a link'}
</PluginLinkTooltip>
<div id={RootHtmlPortalId}/>
</>,
baseState,
);
expect(screen.queryByText('This is a link tooltip')).not.toBeInTheDocument();
userEvent.hover(screen.getByText('This is a link'));
await waitFor(() => {
expect(screen.queryByText('This is a link tooltip')).toBeVisible();
});
act(() => {
userEvent.unhover(screen.getByText('This is a link'));
});
await waitFor(() => {
expect(screen.queryByText('This is a link tooltip')).not.toBeInTheDocument();
});
});
test('should not take focus when the tooltip appears', async () => {
renderWithContext(
<>
<textarea data-testid='textarea'/>
<PluginLinkTooltip
nodeAttributes={{
href: 'https://example.com/tooltip',
}}
>
{'This is a link'}
</PluginLinkTooltip>
<div id={RootHtmlPortalId}/>
</>,
baseState,
);
screen.getByTestId('textarea').focus();
userEvent.hover(screen.getByText('This is a link'));
await waitFor(() => {
expect(screen.queryByText('This is a link tooltip')).toBeVisible();
});
expect(screen.getByTestId('textarea')).toHaveFocus();
act(() => {
userEvent.unhover(screen.getByText('This is a link'));
});
await waitFor(() => {
expect(screen.queryByText('This is a link tooltip')).not.toBeInTheDocument();
});
expect(screen.getByTestId('textarea')).toHaveFocus();
});
test('should not take focus when hovered without a tooltip', async () => {
renderWithContext(
<>
<textarea data-testid='textarea'/>
<PluginLinkTooltip
nodeAttributes={{
href: 'https://example.com',
}}
>
{'This is a link'}
</PluginLinkTooltip>
<div id={RootHtmlPortalId}/>
</>,
baseState,
);
screen.getByTestId('textarea').focus();
userEvent.hover(screen.getByText('This is a link'));
await waitFor(() => {
expect(screen.queryByText('This is a link tooltip')).not.toBeInTheDocument();
});
expect(screen.getByTestId('textarea')).toHaveFocus();
act(() => {
userEvent.unhover(screen.getByText('This is a link'));
});
await waitFor(() => {
expect(screen.queryByText('This is a link tooltip')).not.toBeInTheDocument();
});
expect(screen.getByTestId('textarea')).toHaveFocus();
});
});

Просмотреть файл

@@ -13,11 +13,10 @@ import {
inline,
useTransitionStyles,
FloatingOverlay,
FloatingFocusManager,
useFocus,
} from '@floating-ui/react';
import React, {useState} from 'react';
import type {AnchorHTMLAttributes, ReactElement} from 'react';
import type {AnchorHTMLAttributes, ReactNode} from 'react';
import Pluggable from 'plugins/pluggable';
import {RootHtmlPortalId, OverlaysTimings, OverlayTransitionStyles} from 'utils/constants';
@@ -26,7 +25,7 @@ import './plugin_link_tooltip.scss';
interface Props {
nodeAttributes: AnchorHTMLAttributes<HTMLAnchorElement>;
children: ReactElement;
children: ReactNode;
}
/**
@@ -74,19 +73,17 @@ export default function PluginLinkTooltip(props: Props) {
{isMounted && (
<FloatingPortal id={RootHtmlPortalId}>
<FloatingOverlay className='plugin-link-tooltip-floating-overlay'>
<FloatingFocusManager context={floatingContext}>
<div
ref={setFloating}
style={{...floatingStyles, ...transitionStyles}}
{...getFloatingProps()}
>
<Pluggable
href={props.nodeAttributes.href || ''}
show={true}
pluggableName='LinkTooltip'
/>
</div>
</FloatingFocusManager>
<div
ref={setFloating}
style={{...floatingStyles, ...transitionStyles}}
{...getFloatingProps()}
>
<Pluggable
href={props.nodeAttributes.href || ''}
show={true}
pluggableName='LinkTooltip'
/>
</div>
</FloatingOverlay>
</FloatingPortal>
)}