Skip to content

Commit

Permalink
feat(Tooltip): support ReactElement as content
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelcrespo committed Sep 15, 2023
1 parent b60f972 commit baf2dbd
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 18 deletions.
2 changes: 2 additions & 0 deletions packages/components/tooltip/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ import { Tooltip } from '@contentful/f36-tooltip';
<TextLink>Hover me</TextLink>
</Tooltip>
```

- When using `ReactElement` as the content, it's recommended to use the `ScreenReaderOnly` component when displaying critical information.
23 changes: 23 additions & 0 deletions packages/components/tooltip/src/Tooltip.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event';
import { axe } from '@/scripts/test/axeHelper';

import { Tooltip } from './Tooltip';
import { Paragraph } from '@contentful/f36-typography';

jest.mock('@contentful/f36-core', () => {
const actual = jest.requireActual('@contentful/f36-core');
Expand Down Expand Up @@ -126,4 +127,26 @@ describe('Tooltip', () => {

expect(results).toHaveNoViolations();
});

it('render a React Element as children', async () => {
const user = userEvent.setup();

const { container } = render(
<Tooltip
label="With React Element"
id="Tooltip"
content={<Paragraph>Ich bin ein Paragraph</Paragraph>}
>
<span>Hover me</span>
</Tooltip>,
);
await user.hover(screen.getByText('Hover me'));

const results = await axe(container);

expect(results).toHaveNoViolations();
expect(screen.getByRole('tooltip').textContent).toBe(
'Ich bin ein Paragraph',
);
});
});
31 changes: 25 additions & 6 deletions packages/components/tooltip/src/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ import { getStyles } from './Tooltip.styles';

export type TooltipPlacement = Placement;

type TextContentTooltip = {
/**
* Content of the tooltip
*/
content?: string;
/**
* Accesible label property, only required when using ReactElement as content
*/
label?: string;
};

type RichContentTooltip = {
/**
* Content of the tooltip
*/
content?: React.ReactElement;
/**
* Accesible label property, only required when using ReactElement as content
*/
label: string;
};

export interface TooltipProps extends CommonProps {
/**
* Child nodes to be rendered in the component and that will show the tooltip when they are hovered
Expand All @@ -27,10 +49,6 @@ export interface TooltipProps extends CommonProps {
* HTML element used to wrap the target of the tooltip
*/
as?: React.ElementType;
/**
* Content of the tooltip
*/
content?: string;
/**
* A unique id of the tooltip
*/
Expand Down Expand Up @@ -101,6 +119,7 @@ export const Tooltip = ({
className,
as: HtmlTag = 'span',
content,
label,
id,
isVisible = false,
hideDelay = 0,
Expand All @@ -117,7 +136,7 @@ export const Tooltip = ({
usePortal = false,
isDisabled = false,
...otherProps
}: TooltipProps) => {
}: TooltipProps & (TextContentTooltip | RichContentTooltip)) => {
const styles = getStyles();
const [show, setShow] = useState(isVisible);
const tooltipId = useId(id, 'tooltip');
Expand Down Expand Up @@ -210,7 +229,7 @@ export const Tooltip = ({
}}
{...attributes.popper}
>
<span>{content}</span>
<span aria-label={label}>{content}</span>
<span
className={styles.tooltipArrow}
data-placement={
Expand Down
26 changes: 26 additions & 0 deletions packages/components/tooltip/stories/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SectionHeading } from '@contentful/f36-typography';
import { Tooltip } from '../src/Tooltip';
import { TextLink } from '@contentful/f36-text-link';
import { Flex } from '@contentful/f36-core';
import { css } from 'emotion';

export default {
title: 'Components/Tooltip',
Expand Down Expand Up @@ -212,3 +213,28 @@ export const WithDelays = () => {
</>
);
};

export const WithReactElement = () => {
return (
<>
<SectionHeading as="h3" marginBottom="spacingS">
With React Elements as children
</SectionHeading>

<Flex marginBottom="spacingS">
<Tooltip
isVisible
hideDelay={60000}
label="Render a paragrah with a React Element"
content={
<Flex>
<p className={css({ marginBottom: 0 })}>I'm a React Element</p>
</Flex>
}
>
<TextLink href="/">Hover me</TextLink>
</Tooltip>
</Flex>
</>
);
};
12 changes: 0 additions & 12 deletions packages/forma-36-codemod/transforms/v4-tooltip.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
const { modifyPropsCodemod } = require('./common/modify-props-codemod');
const { hasProperty, getProperty } = require('../utils');

module.exports = modifyPropsCodemod({
componentName: 'Tooltip',
beforeRename: (attributes) => {
if (
hasProperty(attributes, { propertyName: 'content' }) &&
typeof getProperty(attributes, { propertyName: 'content' } !== 'string')
) {
console.error(
'Value of property "content" on Tooltip component should be a string.',
);
}
return attributes;
},
renameMap: {
place: 'placement',
containerElement: 'as',
Expand Down

0 comments on commit baf2dbd

Please sign in to comment.