Files
kycnotme/web/src/components/Tooltip.astro
2025-07-08 09:31:10 +00:00

94 lines
4.5 KiB
Plaintext

---
import { cn } from '../lib/cn'
import type { AstroChildren, AstroComponent, PolymorphicComponent } from '../lib/astro'
import type { HTMLTag } from 'astro/types'
type Props<Component extends AstroComponent | HTMLTag = 'span'> = PolymorphicComponent<Component> & {
children: AstroChildren
text: string
classNames?: {
tooltip?: string
}
color?: 'black' | 'white' | 'zinc-700'
position?: 'bottom' | 'left' | 'right' | 'top'
enabled?: boolean
}
const {
as: Component = 'span',
text,
classNames,
class: className,
color = 'zinc-700',
position = 'top',
enabled = true,
...htmlProps
} = Astro.props
---
<Component {...htmlProps} class={cn('group/tooltip relative overflow-visible', className)}>
<slot />
{
enabled && (
<span
tabindex="-1"
aria-hidden="true"
class={cn(
'pointer-events-none hidden select-none group-hover/tooltip:flex',
'ease-out-cubic scale-75 opacity-0 transition-all transition-discrete duration-100 group-hover/tooltip:scale-100 group-hover/tooltip:opacity-100 starting:group-hover/tooltip:scale-75 starting:group-hover/tooltip:opacity-0',
'z-1000 w-max max-w-sm rounded-lg px-3 py-2 font-sans text-sm font-normal tracking-normal text-pretty wrap-anywhere whitespace-pre-wrap',
// Position classes
{
'absolute -top-2 left-1/2 origin-bottom -translate-x-1/2 translate-y-[calc(-100%+0.5rem)] text-center group-hover/tooltip:-translate-y-full starting:group-hover/tooltip:translate-y-[calc(-100%+0.25rem)]':
position === 'top',
'absolute -bottom-2 left-1/2 origin-top -translate-x-1/2 translate-y-[calc(100%-0.5rem)] text-center group-hover/tooltip:translate-y-full starting:group-hover/tooltip:translate-y-[calc(100%-0.25rem)]':
position === 'bottom',
'absolute top-1/2 -left-2 origin-right translate-x-[calc(-100%+0.5rem)] -translate-y-1/2 text-left group-hover/tooltip:-translate-x-full starting:group-hover/tooltip:translate-x-[calc(-100%+0.25rem)]':
position === 'left',
'absolute top-1/2 -right-2 origin-left translate-x-[calc(100%-0.5rem)] -translate-y-1/2 text-left group-hover/tooltip:translate-x-full starting:group-hover/tooltip:translate-x-[calc(100%-0.25rem)]':
position === 'right',
},
// Arrow position classes
{
'after:absolute after:top-[100%] after:left-1/2 after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-b-transparent after:content-[""]':
position === 'top',
'after:absolute after:bottom-[100%] after:left-1/2 after:-translate-x-1/2 after:border-8 after:border-x-transparent after:border-t-transparent after:content-[""]':
position === 'bottom',
'after:absolute after:top-1/2 after:left-[100%] after:-translate-y-1/2 after:border-8 after:border-y-transparent after:border-r-transparent after:content-[""]':
position === 'left',
'after:absolute after:top-1/2 after:right-[100%] after:-translate-y-1/2 after:border-8 after:border-y-transparent after:border-l-transparent after:content-[""]':
position === 'right',
},
// Background and text color classes
{
'bg-zinc-700 text-white': color === 'zinc-700',
'bg-white text-black': color === 'white',
'bg-black text-white': color === 'black',
},
// Arrow color classes
{
'after:border-t-zinc-700': position === 'top' && color === 'zinc-700',
'after:border-t-white': position === 'top' && color === 'white',
'after:border-t-black': position === 'top' && color === 'black',
'after:border-b-zinc-700': position === 'bottom' && color === 'zinc-700',
'after:border-b-white': position === 'bottom' && color === 'white',
'after:border-b-black': position === 'bottom' && color === 'black',
'after:border-l-zinc-700': position === 'left' && color === 'zinc-700',
'after:border-l-white': position === 'left' && color === 'white',
'after:border-l-black': position === 'left' && color === 'black',
'after:border-r-zinc-700': position === 'right' && color === 'zinc-700',
'after:border-r-white': position === 'right' && color === 'white',
'after:border-r-black': position === 'right' && color === 'black',
},
classNames?.tooltip
)}
set:text={text}
/>
)
}
</Component>