mirror of
https://github.com/tale/headplane.git
synced 2026-08-27 15:37:04 +00:00
feat: redesign tooltips
This commit is contained in:
+69
-26
@@ -1,37 +1,80 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { cloneElement, useRef } from 'react';
|
||||
import {
|
||||
Button as AriaButton,
|
||||
Tooltip as AriaTooltip,
|
||||
TooltipTrigger,
|
||||
} from 'react-aria-components';
|
||||
AriaTooltipProps,
|
||||
mergeProps,
|
||||
useTooltip,
|
||||
useTooltipTrigger,
|
||||
} from 'react-aria';
|
||||
import { TooltipTriggerState, useTooltipTriggerState } from 'react-stately';
|
||||
import cn from '~/utils/cn';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
export interface TooltipProps extends AriaTooltipProps {
|
||||
children: [React.ReactElement, React.ReactElement<TooltipBodyProps>];
|
||||
}
|
||||
|
||||
function Tooltip({ children }: Props) {
|
||||
return <TooltipTrigger delay={0}>{children}</TooltipTrigger>;
|
||||
}
|
||||
function Tooltip(props: TooltipProps) {
|
||||
const state = useTooltipTriggerState({
|
||||
...props,
|
||||
delay: 0,
|
||||
closeDelay: 0,
|
||||
});
|
||||
|
||||
function Button(props: Parameters<typeof AriaButton>[0]) {
|
||||
return <AriaButton {...props} />;
|
||||
}
|
||||
const ref = useRef<HTMLButtonElement | null>(null);
|
||||
const { triggerProps, tooltipProps } = useTooltipTrigger(
|
||||
{
|
||||
...props,
|
||||
delay: 0,
|
||||
closeDelay: 0,
|
||||
},
|
||||
state,
|
||||
ref,
|
||||
);
|
||||
|
||||
function Body({ children, className }: Props) {
|
||||
const [component, body] = props.children;
|
||||
return (
|
||||
<AriaTooltip
|
||||
className={cn(
|
||||
'text-sm max-w-xs p-2 rounded-lg mb-2',
|
||||
'bg-white dark:bg-ui-900 drop-shadow-sm',
|
||||
'border border-gray-200 dark:border-zinc-700',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</AriaTooltip>
|
||||
<span className="relative">
|
||||
<button
|
||||
ref={ref}
|
||||
{...triggerProps}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
{component}
|
||||
</button>
|
||||
{state.isOpen &&
|
||||
cloneElement(body, {
|
||||
...tooltipProps,
|
||||
state,
|
||||
})}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default Object.assign(Tooltip, { Button, Body });
|
||||
interface TooltipBodyProps extends AriaTooltipProps {
|
||||
children: React.ReactNode;
|
||||
state?: TooltipTriggerState;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function Body({ state, className, ...props }: TooltipBodyProps) {
|
||||
const { tooltipProps } = useTooltip(props, state);
|
||||
return (
|
||||
<span
|
||||
{...mergeProps(props, tooltipProps)}
|
||||
className={cn(
|
||||
'absolute z-50 p-3 top-full mt-1',
|
||||
'outline-none rounded-3xl text-sm w-48',
|
||||
'bg-white dark:bg-headplane-950',
|
||||
'text-black dark:text-white',
|
||||
'shadow-lg dark:shadow-md rounded-xl',
|
||||
'border border-headplane-100 dark:border-headplane-800',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default Object.assign(Tooltip, {
|
||||
Body,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user