Skip to content
Draft
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
11 changes: 5 additions & 6 deletions frontend/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ const preview: Preview = {
<Story />
</TamaguiProvider>
),
// Global (rather than living on Tooltip.stories.tsx's meta.decorators)
// so it also covers the autodocs-generated Docs page, which renders the
// component through its own preview pathway and doesn't reliably pick up
// meta-level decorators - without this, Tooltip's Radix primitives throw
// "must be used within TooltipProvider" there even though every actual
// story works fine.
// TooltipProvider is a no-op passthrough since #583 (Tamagui's Tooltip
// needs no ambient ancestor), kept here purely so Tooltip.stories.tsx
// and its autodocs-generated Docs page - which renders the component
// through its own preview pathway and doesn't reliably pick up
// meta-level decorators - don't need their own wrapping.
(Story) => (
<TooltipProvider>
<Story />
Expand Down
59 changes: 0 additions & 59 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"@radix-ui/react-dropdown-menu": "^2.1.19",
"@radix-ui/react-popover": "^1.1.18",
"@radix-ui/react-tabs": "^1.1.16",
"@radix-ui/react-tooltip": "^1.2.8",
"@tamagui/config": "^2.7.6",
"@tamagui/core": "^2.7.6",
"@tamagui/vite-plugin": "^2.7.6",
Expand Down
19 changes: 13 additions & 6 deletions frontend/src/components/Tooltip/Tooltip.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,37 @@
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.18);
font-size: 0.875rem;
line-height: 1.4;
transform-origin: var(--radix-tooltip-content-transform-origin);
// Tamagui sets transform-origin inline itself (computed from the actual
// flip/shift middleware result), unlike Radix's CSS-var handoff.
animation-duration: v.$duration-fast;
animation-timing-function: v.$easing-standard;
animation-fill-mode: both;

&[data-side='top'] {
// Tamagui's `data-placement` is the full placement ("top", "top-start",
// "bottom-end", ...), not just the side Radix's `data-side` gave us -
// prefix-match to key the slide direction off the side alone.
&[data-placement^='top'] {
animation-name: tooltip-slide-up;
}

&[data-side='bottom'] {
&[data-placement^='bottom'] {
animation-name: tooltip-slide-down;
}

&[data-side='left'] {
&[data-placement^='left'] {
animation-name: tooltip-slide-left;
}

&[data-side='right'] {
&[data-placement^='right'] {
animation-name: tooltip-slide-right;
}
}

.arrow {
fill: rgba(c.$color-bg-invert, 0.96);
// Tamagui's Arrow is a rotated box (border/background), not an SVG
// polygon like Radix's - background-color is what actually paints it.
background-color: rgba(c.$color-bg-invert, 0.96);
border-width: 0;
}

@keyframes tooltip-slide-up {
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/Tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import Button from '../Button/Button';

/**
* `Tooltip` wraps a single focusable trigger element and shows supplementary
* content on click/tap or focus via Radix — hover never opens it, on either
* desktop or mobile (see #568). Clicking/tapping the trigger again, clicking
* anywhere else, or pressing Escape closes it. It must be nested under a
* `TooltipProvider` (mounted once near the app root, and globally in
* content on click/tap or focus via Tamagui — hover never opens it, on
* either desktop or mobile (see #568). Clicking/tapping the trigger again,
* clicking anywhere else, or pressing Escape closes it. It must be nested
* under a `TamaguiProvider` (mounted once near the app root, and globally in
* .storybook/preview.tsx). Use tooltips only for supplementary context -
* essential information must remain available without clicking or focusing.
*/
Expand All @@ -35,7 +35,7 @@ export const Default: Story = {
const trigger = canvas.getByRole('button', { name: 'Click or focus me' });
await userEvent.tab();
await expect(trigger).toHaveFocus();
// Tooltip content renders via a Radix Portal into document.body.
// Tooltip content renders via a Tamagui Portal into document.body.
const tooltip = await within(canvasElement.ownerDocument.body).findByRole('tooltip');
await expect(tooltip).toHaveTextContent('Additional context shown on click/tap or focus');
},
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/components/Tooltip/Tooltip.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
import { describe, it, expect } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { render as rtlRender, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { TamaguiProvider } from 'tamagui';
import Tooltip, { TooltipProvider } from './Tooltip';
import tamaguiConfig from '../../../tamagui.config';

// Tamagui's Tooltip (#583) needs a TamaguiProvider ancestor - unlike Radix's
// Tooltip.Root, it isn't usable standalone. The app root (src/main.tsx)
// provides this in production; tests need their own.
function render(...args: Parameters<typeof rtlRender>) {
const [ui, options] = args;
return rtlRender(ui, {
wrapper: ({ children }) => (
<TamaguiProvider config={tamaguiConfig} defaultTheme="light">
{children}
</TamaguiProvider>
),
...options,
});
}

function renderTooltip() {
render(
Expand Down
Loading