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

feat(Tooltip): use popover API #2916

Merged
merged 28 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dac435f
feat(Tooltip): use popover API
Barsnes Dec 18, 2024
3ff1c3a
add delay and focus
Barsnes Dec 18, 2024
53f0f89
las fixes
Barsnes Dec 18, 2024
580e8a4
Merge branch 'next' into tooltip/popover
Barsnes Dec 18, 2024
1dde151
update tests
Barsnes Dec 18, 2024
1909944
same delay as we used to have
Barsnes Dec 18, 2024
7180444
fix showcase portal
Barsnes Dec 18, 2024
375f40d
add exc, remove preventDefault to make button action work
Barsnes Dec 19, 2024
e6300c7
correct css vars for arrow
Barsnes Dec 19, 2024
c655c59
from review
Barsnes Dec 19, 2024
b07e9eb
mouseenter
Barsnes Dec 19, 2024
f7f1bd2
Merge branch 'next' into tooltip/popover
Barsnes Dec 19, 2024
53bdef8
popovertargetaction='show'
Barsnes Dec 19, 2024
317eb5e
remove delay prop
Barsnes Dec 19, 2024
3121b1c
remove id from preview story
Barsnes Dec 19, 2024
6fb92a4
fix(Tooltip): safari rendering
eirikbacker Dec 19, 2024
b556747
Merge branch 'next' into tooltip/popover
Barsnes Dec 19, 2024
ffc0b65
Create red-chefs-refuse.md
Barsnes Dec 19, 2024
26b1f4b
add kjent mangler, and remove safari support
Barsnes Dec 20, 2024
19c39c7
always close when moving away from trigger
Barsnes Dec 20, 2024
f0af89c
add listeners to element and not effect
Barsnes Dec 20, 2024
4608f1e
Merge branch 'next' into tooltip/popover
Barsnes Dec 20, 2024
579def0
update docs
Barsnes Dec 20, 2024
b115b69
Merge branch 'next' into tooltip/popover
Barsnes Dec 20, 2024
f87448a
Merge branch 'next' into tooltip/popover
Barsnes Jan 2, 2025
5920355
update kjent mangler
Barsnes Jan 2, 2025
514a2a5
Update red-chefs-refuse.md
Barsnes Jan 2, 2025
de2834a
Merge branch 'next' into tooltip/popover
Barsnes Jan 2, 2025
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
2 changes: 1 addition & 1 deletion apps/_components/src/Showcase/Showcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function Showcase({ className, ...props }: ShowcaseProps) {
placeholder='[email protected]'
className={classes.userField}
/>
<Tooltip content='Trykk for å få hjelp' portal={false}>
<Tooltip content='Trykk for å få hjelp'>
<Link href='#' className={classes.userLink}>
Glemt passord?
</Link>
Expand Down
17 changes: 15 additions & 2 deletions packages/css/src/tooltip.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@
--dsc-tooltip-border-radius: var(--ds-border-radius-default);
--dsc-tooltip-padding: var(--ds-spacing-1) var(--ds-spacing-2);
--dsc-tooltip-arrow-size: var(--ds-spacing-2);
--dsc-tooltip-transition-duration: 0.2s;
--dsc-tooltip-transition-delay: 150ms;

position: fixed;
background: var(--dsc-tooltip-background);
border-radius: var(--dsc-tooltip-border-radius);
box-sizing: border-box;
border: none;
border-width: 0;
color: var(--dsc-tooltip-color);
line-height: var(--ds-line-height-sm);
padding: var(--dsc-tooltip-padding);
overflow: visible;
margin: 0; /* Needed to place tooltip correctly, since popover adds margin */
transition-property: opacity;
transition-delay: var(--dsc-tooltip-transition-delay);
transition-duration: var(--dsc-tooltip-transition-duration);
transition-timing-function: ease-in-out;
opacity: 0;

&::before {
content: '';
Expand All @@ -19,11 +31,12 @@
height: var(--dsc-tooltip-arrow-size);
width: var(--dsc-tooltip-arrow-size);
position: absolute;
left: var(--ds-tooltip-arrow-x);
top: var(--ds-tooltip-arrow-y);
left: var(--dsc-tooltip-arrow-x);
top: var(--dsc-tooltip-arrow-y);
translate: -50% -50%;
rotate: 45deg;
}

@media (forced-colors: active) {
--dsc-tooltip-background: CanvasText;
}
Expand Down
15 changes: 1 addition & 14 deletions packages/react/src/components/Tooltip/Tooltip.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,7 @@ Vurder om `tooltip` skal plasseres over, under eller ved siden av elementet.

<Canvas of={TooltipStories.Placement} />

### Åpen som standard

<Canvas of={TooltipStories.DefaultOpen} />

### Portal

<Canvas of={TooltipStories.Portal} />

### Fargevarianter

`Tooltip` har to fargevarianter i `neutral`, tilpasset `light` og `dark` modus.

<br/ >
### CSS Variabler
## CSS Variabler

<CssVariables css={css} />
<br/ >
Expand Down
23 changes: 1 addition & 22 deletions packages/react/src/components/Tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default {
} satisfies Meta;

export const Preview: StoryFn<typeof Tooltip> = (args) => (
<Tooltip {...args}>
<Tooltip {...args} id='my-tooltip'>
<Button>My trigger</Button>
</Tooltip>
);
Expand All @@ -40,24 +40,3 @@ export const Placement: Story = {
children: defaultChildren,
},
};

export const DefaultOpen: Story = {
args: {
content: 'Tooltip text',
defaultOpen: true,
children: defaultChildren,
},
play: async () => {
// Wait 500 ms to let tooltip fade in before running tests
await new Promise((resolve) => setTimeout(resolve, 500));
},
};

export const Portal: Story = {
args: {
content: 'Tooltip text',
children: defaultChildren,
placement: 'top',
portal: true,
},
};
90 changes: 37 additions & 53 deletions packages/react/src/components/Tooltip/Tooltip.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const render = async (props: Partial<TooltipProps> = {}) => {
const allProps: TooltipProps = {
children: <button>My button</button>,
content: 'Tooltip text',
delay: 0,
...props,
};
/* Flush microtasks */
Expand All @@ -18,78 +17,63 @@ const render = async (props: Partial<TooltipProps> = {}) => {

return {
user,
...renderRtl(<Tooltip {...allProps} />),
...renderRtl(
<Tooltip
{...allProps}
style={{
// @ts-ignore react does not want us to set css vars here
'--dsc-tooltip-transition-duration': '0s',
}}
/>,
),
};
};

describe('Tooltip', () => {
describe('should render children', () => {
it('should render child', async () => {
await render();
const tooltipTrigger = screen.getByRole('button', { name: 'My button' });
it('should render child', async () => {
await render();
const tooltipTrigger = screen.getByRole('button', { name: 'My button' });

expect(tooltipTrigger).toBeInTheDocument();
});
expect(tooltipTrigger).toBeInTheDocument();
});

describe('should render tooltip', () => {
it('should render tooltip on hover', async () => {
const { user } = await render();
const tooltipTrigger = screen.getByRole('button', { name: 'My button' });

expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
it('should render tooltip on hover', async () => {
const { user } = await render();
const tooltipTrigger = screen.getByRole('button');

await act(async () => await user.hover(tooltipTrigger));
expect(screen.getByText('Tooltip text')).not.toBeVisible();

const tooltip = await screen.findByText('Tooltip text');
expect(tooltip).toBeInTheDocument();
expect(screen.queryByRole('tooltip')).toBeInTheDocument();
});
await act(async () => await user.hover(tooltipTrigger));

it('should render tooltip on focus', async () => {
const { user } = await render();
const tooltip = await screen.findByText('Tooltip text');
expect(tooltip).toBeVisible();
expect(screen.getByText('Tooltip text')).toBeVisible();
});

expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'My button' }));
const tooltip = await screen.findByText('Tooltip text');
expect(tooltip).toBeInTheDocument();
expect(screen.queryByRole('tooltip')).toBeInTheDocument();
});
it('should render tooltip on focus', async () => {
const { user } = await render();

it('should close tooltip on escape', async () => {
const { user } = await render();
const tooltipTrigger = screen.getByRole('button', { name: 'My button' });

expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
await act(async () => {
await user.hover(tooltipTrigger);
});
const tooltip = await screen.findByText('Tooltip text');
expect(tooltip).toBeInTheDocument();
await act(async () => {
await user.keyboard('[Escape]');
});
expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
});
expect(screen.queryByText('Tooltip text')).not.toBeVisible();
await user.click(screen.getByRole('button', { name: 'My button' }));
const tooltip = await screen.findByText('Tooltip text');
expect(tooltip).toBeInTheDocument();
expect(screen.queryByRole('tooltip')).toBeVisible();
});

it('should render open when we pass open prop', async () => {
await render({ open: true });
const tooltipTrigger = screen.getByRole('button', { name: 'My button' });

expect(screen.getByRole('tooltip')).toBeInTheDocument();
expect(tooltipTrigger).toHaveAttribute('aria-describedby');
expect(screen.getByRole('tooltip')).toBeVisible();
});

it('should have delay', async () => {
const { user } = await render({ delay: 300 });

await act(async () => await user.hover(screen.getByRole('button')));
expect(screen.queryByRole('tooltip')).toBeNull();

await vi.waitFor(() => {
expect(screen.queryByRole('tooltip')).toBeVisible();
it('should have correct id and popovertarget attributes', async () => {
await render({
id: 'my-tooltip',
});
const trigger = screen.getByRole('button');
const popover = screen.getByText('Tooltip text');

expect(trigger.getAttribute('popovertarget')).toBe(popover.id);
});

it('should render span when children is a string', async () => {
Expand Down
Loading
Loading