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>
This commit is contained in:
102
src/components/atoms/Tooltip/Tooltip.tsx
Normal file
102
src/components/atoms/Tooltip/Tooltip.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
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>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user