Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BC(web, web-twig) Refactor(web-react): Tooltip - Remove deprectations and changed internal classnames #1451

Merged
merged 6 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions docs/migrations/web/MIGRATION-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Introducing version 2 of the _spirit-web_ package
- [Modal: Custom Height](#modal-custom-height)
- [Modal: Uniform Variant Feature Flag](#modal-uniform-variant-feature-flag)
- [Grid: GridSpan Component](#grid-gridspan-component)
- [Tooltip: Data Selector Controlled Placement Feature Flag](#tooltip-data-selector-controlled-placement-feature-flag)
- [Tooltip: FloatingUI only](#tooltip-floatingui-only)

## General Changes

Expand Down Expand Up @@ -186,20 +186,23 @@ The `GridSpan` component was removed and the `GridItem` component should be used
- `column-start` = 1 + (12 - 6) / 2 = 4
- `column-start` = 1 + (12 - 4) / 2 = 5

### Tooltip: Data-Selector-Controlled Placement Feature Flag
### Tooltip: FloatingUI only

The feature flag enabling the data-selector-controlled placement (`data-spirit-placement-controlled`)
for tooltip was removed and the data-selector-controlled placement is the default.
Non-FloatingUI and CSS-only Tooltips are no longer supported. The Tooltip component is now dependent on the FloatingUI library and has a new structure.
See the updated [Tooltip Readme][readme-tooltip] for more details on how to use Tooltip now.
The feature flag enabling the data-selector-controlled placement (`data-spirit-placement-controlled`) for the tooltip was removed.

#### Migration Guide

You can now safely delete the CSS class `.spirit-feature-tooltip-enable-data-placement` and/or the Sass variable
`$tooltip-enable-data-placement` from your project as they have no effect.
Please follow new Tooltip structure.

---

Please refer back to these instructions or reach out to our team if you encounter any issues during migration.

[dictionary-placement]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#placement
[readme-deprecations]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web/README.md#deprecations
[readme-feature-flags]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web/README.md#feature-flags
[dictionary-placement]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#placement
[readme-tooltip]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web/src/scss/components/Tooltip/README.md
18 changes: 15 additions & 3 deletions packages/web-react/src/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import classNames from 'classnames';
import React, { useRef } from 'react';
import { useStyleProps } from '../../hooks';
import { SpiritTooltipProps } from '../../types';
import { TooltipProvider } from './TooltipContext';
import { useFloating } from './useFloating';
import { useTooltipStyleProps } from './useTooltipStyleProps';

const Tooltip = (props: SpiritTooltipProps) => {
const {
Expand All @@ -20,10 +22,15 @@ const Tooltip = (props: SpiritTooltipProps) => {
onToggle,
placement: tooltipPlacement,
trigger = ['click', 'hover'],
...rest
...restProps
} = props;

const { styleProps, props: otherProps } = useStyleProps({ ...rest });
const { classProps, props: modifiedProps } = useTooltipStyleProps({
isDismissible,
isOpen,
...restProps,
});
const { styleProps, props: otherProps } = useStyleProps(modifiedProps);

// Refs for FloatingUI
const arrowRef = useRef<HTMLSpanElement>(null);
Expand Down Expand Up @@ -90,7 +97,12 @@ const Tooltip = (props: SpiritTooltipProps) => {
y,
}}
>
<div ref={tooltipRef} {...styleProps} {...otherProps}>
<div
{...otherProps}
ref={tooltipRef}
className={classNames(classProps.rootClassName, styleProps.className)}
style={styleProps.style}
>
{children}
</div>
</TooltipProvider>
Expand Down
4 changes: 2 additions & 2 deletions packages/web-react/src/components/Tooltip/TooltipPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const TooltipPopover = (props: TooltipPopoverProps) => {
placement,
...rest,
});
const { styleProps: contentStyleProps, props: contentOtherProps } = useStyleProps({ ...modifiedProps });
const { styleProps: contentStyleProps, props: contentOtherProps } = useStyleProps(modifiedProps);

const renderCloseButton = useMemo(
() => isDismissible && <TooltipCloseButton onClick={() => onToggle(false)} label="close" />,
Expand Down Expand Up @@ -79,7 +79,7 @@ const TooltipPopover = (props: TooltipPopoverProps) => {
return (
<div
ref={tooltipRef}
className={classNames(classProps.rootClassName, contentStyleProps.className)}
className={classNames(classProps.popoverClassName, contentStyleProps.className)}
{...contentOtherProps}
{...getFloatingProps()}
style={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { Button } from '../../Button';
import { Tooltip, TooltipTrigger, TooltipPopover } from '..';
import { Tooltip, TooltipPopover, TooltipTrigger } from '..';

describe('Tooltip', () => {
const id = 'TooltipTest';
Expand All @@ -19,46 +19,41 @@ describe('Tooltip', () => {
const onToggle = () => null;
const open = true;

const dom = render(
render(
<Tooltip id={id} isOpen={open} onToggle={onToggle}>
<TooltipTrigger>{triggerText}</TooltipTrigger>
<TooltipPopover>{popoverText}</TooltipPopover>
</Tooltip>,
);

const triggerElement = dom.container.querySelector(`#${id}`) as HTMLElement;
const popoverElement = dom.container.querySelector('[data-spirit-element="tooltip"]') as HTMLElement;

expect(triggerElement.textContent).toBe(triggerText);
expect(popoverElement.textContent).toBe(popoverText);
expect(screen.getByRole('button')).toHaveTextContent(triggerText);
expect(screen.getByRole('tooltip')).toHaveTextContent(popoverText);
});

it('should be opened', () => {
const onToggle = jest.fn();

const dom = render(
render(
<Tooltip id={id} isOpen onToggle={onToggle}>
<TooltipTrigger elementType={Button}>trigger</TooltipTrigger>
<TooltipPopover>{popoverText}</TooltipPopover>
</Tooltip>,
);
const element = dom.container.querySelector('.Tooltip') as HTMLElement;

expect(element).not.toHaveClass('is-hidden');
expect(screen.getByRole('tooltip')).not.toHaveClass('is-hidden');
});

it('should call toggle function', () => {
const onToggle = jest.fn();

const dom = render(
render(
<Tooltip id={id} isOpen={false} onToggle={onToggle}>
<TooltipTrigger elementType={Button}>trigger</TooltipTrigger>
<TooltipPopover>Hello World</TooltipPopover>
</Tooltip>,
);
const trigger = dom.container.querySelector(`button#${id}`) as HTMLElement;

fireEvent.click(trigger);
fireEvent.click(screen.getByRole('button'));

expect(onToggle).toHaveBeenCalled();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { render } from '@testing-library/react';
import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { TooltipPopover } from '..';

describe('TooltipPopover', () => {
classNamePrefixProviderTest(TooltipPopover, 'Tooltip');
classNamePrefixProviderTest(TooltipPopover, 'TooltipPopover');

stylePropsTest((props) => <TooltipPopover {...props} data-testid="TooltipPopover-test" />, 'TooltipPopover-test');

Expand All @@ -16,9 +16,8 @@ describe('TooltipPopover', () => {
it('should render tooltip popover', () => {
const popoverText = 'TooltipPopover';

const dom = render(<TooltipPopover>{popoverText}</TooltipPopover>);
const element = dom.container.querySelector('.Tooltip') as HTMLElement;
render(<TooltipPopover data-testid="test-tooltipPopover">{popoverText}</TooltipPopover>);

expect(element.textContent).toBe(popoverText);
expect(screen.getByTestId('test-tooltipPopover').textContent).toBe(popoverText);
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { render } from '@testing-library/react';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
import { Button } from '../../Button';
Expand All @@ -12,12 +12,10 @@ describe('TooltipTrigger', () => {
restPropsTest((props) => <TooltipTrigger elementType={Button} {...props} />, 'button');

it('should render tooltip trigger', () => {
const id = 'TooltipTriggerTest';
const triggerText = 'TooltipTrigger';

const dom = render(<TooltipTrigger data-spirit-testid={id}>{triggerText}</TooltipTrigger>);
const element = dom.container.querySelector(`[data-spirit-testid="${id}"]`) as HTMLElement;
render(<TooltipTrigger>{triggerText}</TooltipTrigger>);

expect(element.textContent).toBe(triggerText);
expect(screen.getByRole('button')).toHaveTextContent(triggerText);
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { render } from '@testing-library/react';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
import UncontrolledTooltip from '../UncontrolledTooltip';
Expand All @@ -13,9 +13,12 @@ describe('UncontrolledTooltip', () => {
restPropsTest(UncontrolledTooltip, 'div');

it('should render text children', () => {
const dom = render(<UncontrolledTooltip id="uncontrolled-tooltip">Hello World</UncontrolledTooltip>);
const element = dom.container.querySelector('div') as HTMLElement;
render(
<UncontrolledTooltip data-testid="test-tooltip" id="uncontrolled-tooltip">
Hello World
</UncontrolledTooltip>,
);

expect(element.textContent).toBe('Hello World');
expect(screen.getByTestId('test-tooltip')).toHaveTextContent('Hello World');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ describe('useTooltipStyleProps', () => {
const { result } = renderHook(() => useTooltipStyleProps({}));

expect(result.current.classProps.rootClassName).toBe('Tooltip');
expect(result.current.classProps.arrowClassName).toBe('Tooltip__arrow');
expect(result.current.classProps.closeButtonClassName).toBe('Tooltip__close');
expect(result.current.classProps.arrowClassName).toBe('TooltipPopover__arrow');
pavelklibani marked this conversation as resolved.
Show resolved Hide resolved
expect(result.current.classProps.closeButtonClassName).toBe('TooltipPopover__close');
});

it('should return dismissible class', () => {
const { result } = renderHook(() => useTooltipStyleProps({ isDismissible: true }));

expect(result.current.classProps.rootClassName).toBe('Tooltip Tooltip--dismissible');
expect(result.current.classProps.popoverClassName).toBe('TooltipPopover TooltipPopover--dismissible');
});
});
22 changes: 10 additions & 12 deletions packages/web-react/src/components/Tooltip/useTooltipStyleProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface UseTooltipStyleProps extends TooltipProps {}
export interface UseTooltipStylePropsReturn {
classProps: {
rootClassName: string;
wrapperClassName: string;
popoverClassName: string;
arrowClassName: string;
closeButtonClassName: string;
};
Expand All @@ -20,27 +20,25 @@ export interface UseTooltipStylePropsReturn {
export const useTooltipStyleProps = (props: Omit<UseTooltipStyleProps, omittedProps>): UseTooltipStylePropsReturn => {
const { isDismissible, isOpen, ...modifiedProps } = props;
const tooltipClass = useClassNamePrefix('Tooltip');
const tooltipWrapperClass = `${tooltipClass}Wrapper`;
const arrowClass = `${tooltipClass}__arrow`;
const closeButtonClass = `${tooltipClass}__close`;
const rootDismissibleClass = `${tooltipClass}--dismissible`;
const tooltipPopoverClass = `${tooltipClass}Popover`;
const arrowClass = `${tooltipPopoverClass}__arrow`;
const closeButtonClass = `${tooltipPopoverClass}__close`;
const rootDismissibleClass = `${tooltipPopoverClass}--dismissible`;
const rootHiddenClass = 'is-hidden';

const isHiddenClass = useMemo(() => isOpen === false, [isOpen]);

const tooltipClassName = classNames(tooltipClass, {
const tooltipPopoverClassName = classNames(tooltipPopoverClass, {
[rootDismissibleClass]: isDismissible,
[rootHiddenClass]: isHiddenClass,
});
const arrowClassName = arrowClass;
const closeButtonClassName = closeButtonClass;

return {
classProps: {
rootClassName: tooltipClassName,
wrapperClassName: tooltipWrapperClass,
arrowClassName,
closeButtonClassName,
rootClassName: tooltipClass,
popoverClassName: tooltipPopoverClassName,
arrowClassName: arrowClass,
closeButtonClassName: closeButtonClass,
},
props: modifiedProps,
};
Expand Down
Loading
Loading