Files
ADS3-Design-System/src/components/atoms/Tooltip/Tooltip.tsx
Richie 722475215d Reorganise components into atoms/molecules/organisms and fix Input icon colours
Moved all 17 components from ui/ into atomic design tiers: atoms (Button,
IconButton, Input, Textarea, Select, Checkbox, Radio, Switch, Badge, Tag,
Chip, Tooltip) and molecules (Alert, Accordion, Card, Dialog, Popover).
Updated all Storybook titles and cross-component imports. Changed Input
icons to primary-dark and replaced palette token references with semantic
tokens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-22 09:10:12 +10:00

103 lines
2.2 KiB
TypeScript

import {
useState,
useRef,
cloneElement,
isValidElement,
type ReactElement,
type ReactNode,
} from 'react'
import {
useFloating,
useHover,
useFocus,
useDismiss,
useRole,
useInteractions,
offset,
flip,
shift,
arrow,
FloatingArrow,
FloatingPortal,
autoUpdate,
type Placement,
} from '@floating-ui/react'
import { cn } from '@/lib/utils'
export interface TooltipProps {
content: ReactNode
placement?: Placement
delay?: number | { open?: number; close?: number }
children: ReactElement
className?: string
}
export function Tooltip({
content,
placement = 'top',
delay = { open: 400, close: 0 },
children,
className,
}: TooltipProps) {
const [open, setOpen] = useState(false)
const arrowRef = useRef(null)
const { refs, floatingStyles, context } = useFloating({
open,
onOpenChange: setOpen,
placement,
whileElementsMounted: autoUpdate,
middleware: [
offset(8),
flip({ fallbackAxisSideDirection: 'start' }),
shift({ padding: 8 }),
arrow({ element: arrowRef }),
],
})
const hover = useHover(context, { delay })
const focus = useFocus(context)
const dismiss = useDismiss(context)
const role = useRole(context, { role: 'tooltip' })
const { getReferenceProps, getFloatingProps } = useInteractions([
hover,
focus,
dismiss,
role,
])
if (!isValidElement(children)) return children
return (
<>
{cloneElement(children, {
ref: refs.setReference,
...getReferenceProps(),
} as Record<string, unknown>)}
{open && (
<FloatingPortal>
<div
ref={refs.setFloating}
style={floatingStyles}
className={cn(
'z-50 max-w-xs rounded-default bg-surface px-3 py-1.5 font-sans text-small text-text shadow-md',
className,
)}
{...getFloatingProps()}
>
{content}
<FloatingArrow
ref={arrowRef}
context={context}
className="fill-surface drop-shadow-sm"
width={12}
height={6}
/>
</div>
</FloatingPortal>
)}
</>
)
}