diff --git a/src/components/ui/overlayPresence.test.tsx b/src/components/ui/overlayPresence.test.tsx new file mode 100644 index 00000000..53886710 --- /dev/null +++ b/src/components/ui/overlayPresence.test.tsx @@ -0,0 +1,60 @@ +import { render, screen } from '@testing-library/react' +import { describe, expect, it } from 'vitest' +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from './tooltip' +import { + Popover, + PopoverContent, + PopoverTrigger, +} from './popover' + +const PRESENCE_ANIMATION_CLASS_PARTS = [ + 'animate-', + 'fade-', + 'zoom-', + 'slide-in-from', +] + +function expectNoPresenceAnimationClasses(element: HTMLElement) { + const unstableClasses = element.className + .split(/\s+/) + .filter((className) => + PRESENCE_ANIMATION_CLASS_PARTS.some((part) => className.includes(part)), + ) + + expect(unstableClasses).toEqual([]) +} + +describe('overlay presence stability', () => { + it('keeps tooltip content free of Radix presence animation classes', () => { + render( + + + + + + Tooltip copy + + , + ) + + expectNoPresenceAnimationClasses(screen.getByTestId('tooltip-content')) + }) + + it('keeps popover content free of Radix presence animation classes', () => { + render( + + + + + Popover copy + , + ) + + expectNoPresenceAnimationClasses(screen.getByTestId('popover-content')) + }) +}) diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx index c618fe7e..c98c434b 100644 --- a/src/components/ui/popover.tsx +++ b/src/components/ui/popover.tsx @@ -30,7 +30,7 @@ function PopoverContent({ sideOffset={sideOffset} collisionPadding={collisionPadding} className={cn( - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-[12000] w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden", + "bg-popover text-popover-foreground z-[12000] w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden", className )} {...props} @@ -45,39 +45,48 @@ function PopoverAnchor({ return } -function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) +interface PopoverTextSlotProps extends React.HTMLAttributes { + baseClassName: string + element: "div" | "p" + slot: string } -function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) { - return ( -
- ) -} - -function PopoverDescription({ +function PopoverTextSlot({ + baseClassName, className, + element, + slot, ...props -}: React.ComponentProps<"p">) { +}: PopoverTextSlotProps) { + return React.createElement( + element, + { + "data-slot": slot, + className: cn(baseClassName, className), + ...props, + }, + ) +} + +function PopoverHeader(props: React.ComponentProps<"div">) { return ( -

) } +function PopoverTitle(props: React.ComponentProps<"div">) { + return +} + +function PopoverDescription(props: React.ComponentProps<"p">) { + return +} + export { Popover, PopoverTrigger, diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx index d80a1446..62345776 100644 --- a/src/components/ui/tooltip.tsx +++ b/src/components/ui/tooltip.tsx @@ -42,7 +42,7 @@ function TooltipContent({ data-slot="tooltip-content" sideOffset={sideOffset} className={cn( - "bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", + "bg-foreground text-background z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", className )} {...props}