feat: add tooltip

This commit is contained in:
p-sw 2024-05-21 12:43:05 +09:00
parent 208699743f
commit 98c853d73e
2 changed files with 158 additions and 0 deletions

View File

@ -0,0 +1,93 @@
import React, { useState } from "react";
import { VariantProps, vcn } from "../shared";
interface TooltipContextBody {
position: "top" | "bottom" | "left" | "right";
}
const Tooltip$Context$InitialState: TooltipContextBody = {
position: "top",
};
const Tooltip$Context = React.createContext<
[TooltipContextBody, React.Dispatch<React.SetStateAction<TooltipContextBody>>]
>([Tooltip$Context$InitialState, () => {}]);
const [Tooltip$Variant, Tooltip$resolveVariantProps] = vcn({
base: "w-fit h-fit relative group/tooltip",
variants: {
position: {
top: "",
bottom: "",
left: "",
right: "",
},
},
defaults: {
position: "top",
},
});
interface TooltipProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof Tooltip$Variant> {}
const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>((props, ref) => {
const [variantProps, rest] = Tooltip$resolveVariantProps(props);
const contextState = useState<TooltipContextBody>({
...Tooltip$Context$InitialState,
...variantProps,
});
return (
<Tooltip$Context.Provider value={contextState}>
<div ref={ref} className={Tooltip$Variant(variantProps)} {...rest} />
</Tooltip$Context.Provider>
);
});
const [TooltipContent$Variant, TooltipContent$resolveVariantProps] = vcn({
base: "absolute py-1 px-3 bg-white dark:bg-black border border-black/10 dark:border-white/20 [--tooltip-offset:2px] opacity-0 group-hover/tooltip:opacity-100 pointer-events-none group-hover/tooltip:pointer-events-auto transition-all rounded-md",
variants: {
position: {
top: "bottom-[calc(100%+var(--tooltip-offset))] left-1/2 -translate-x-1/2 group-hover/tooltip:translate-y-0 translate-y-[10px]",
bottom:
"top-[calc(100%+var(--tooltip-offset))] left-1/2 -translate-x-1/2 group-hover/tooltip:translate-y-0 translate-y-[-10px]",
left: "right-[calc(100%+var(--tooltip-offset))] top-1/2 -translate-y-1/2 group-hover/tooltip:translate-x-0 translate-x-[10px]",
right:
"left-[calc(100%+var(--tooltip-offset))] top-1/2 -translate-y-1/2 group-hover/tooltip:translate-x-0 translate-x-[-10px]",
},
offset: {
sm: "[--tooltip-offset:2px]",
md: "[--tooltip-offset:4px]",
lg: "[--tooltip-offset:8px]",
},
},
defaults: {
position: "top",
offset: "md",
},
});
interface TooltipContentProps
extends React.HTMLAttributes<HTMLDivElement>,
Omit<VariantProps<typeof TooltipContent$Variant>, "position"> {}
const TooltipContent = React.forwardRef<HTMLDivElement, TooltipContentProps>(
(props, ref) => {
const [variantProps, rest] = TooltipContent$resolveVariantProps(props);
const [contextState] = React.useContext(Tooltip$Context);
return (
<div
ref={ref}
className={TooltipContent$Variant({
...variantProps,
position: contextState.position,
})}
{...rest}
/>
);
}
);
export { Tooltip, TooltipContent };

View File

@ -0,0 +1,65 @@
import { Button } from "../components/Button";
import { Tooltip, TooltipContent } from "../components/Tooltip";
export default {
title: "React/Tooltip",
component: Tooltip,
parameters: {
layout: "centered",
},
};
export const Default = () => {
return (
<Tooltip>
<TooltipContent>
<p className="whitespace-nowrap">Hello World!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
};
export const Top = () => {
return (
<Tooltip position="top">
<TooltipContent>
<p className="whitespace-nowrap">Hello World!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
};
export const Bottom = () => {
return (
<Tooltip position="bottom">
<TooltipContent>
<p className="whitespace-nowrap">Hello World!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
};
export const Left = () => {
return (
<Tooltip position="left">
<TooltipContent>
<p className="whitespace-nowrap">Hello World!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
};
export const Right = () => {
return (
<Tooltip position="right">
<TooltipContent>
<p className="whitespace-nowrap">Hello World!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
};