From 4d4192c0f0917b7f233e96c6c50336418be42d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Wed, 25 Dec 2024 09:28:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Tooltip=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Tooltip.module.css | 66 +++++++++++++++++++++++++++++++ src/components/Tooltip.tsx | 46 +++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/components/Tooltip.module.css create mode 100644 src/components/Tooltip.tsx diff --git a/src/components/Tooltip.module.css b/src/components/Tooltip.module.css new file mode 100644 index 0000000..7977457 --- /dev/null +++ b/src/components/Tooltip.module.css @@ -0,0 +1,66 @@ +@layer components { + .tooltip_container { + position: relative; + display: inline-block; + } + .tooltip { + position: absolute; + padding-inline: calc(var(--spacing) * 3); + padding-block: calc(var(--spacing) * 1); + border-radius: var(--border-radius-xxs); + color: light-dark( + oklch(from var(--color-neutral) calc(l + (1 - l) * 0.8) c h), + oklch(from var(--color-neutral) calc(l + (1 - l) * 0.7) c h) + ); + background-color: light-dark( + oklch(from var(--color-qianbai) calc(l * 0.6) c h), + oklch(from var(--color-qihei) calc(l + (1 - l) * 0.2) c h) + ); + font-size: var(--font-size-m); + width: fit-content; + max-width: 40em; + text-wrap: balance; + word-break: keep-all; + box-shadow: 0 4px 6px -1px oklch(from var(--color-black) l c h / 0.1), + 0 2px 4px -2px oklch(from var(--color-black) l c h / 0.1); + pointer-events: none; + &.top { + bottom: 100%; + left: 50%; + transform: translateX(-50%); + margin-bottom: calc(var(--spacing) * 4); + } + &.bottom { + top: 100%; + left: 50%; + transform: translateX(-50%); + margin-top: calc(var(--spacing) * 4); + } + &.left { + top: 50%; + right: 100%; + transform: translateY(-50%); + margin-right: calc(var(--spacing) * 4); + } + &.right { + top: 50%; + left: 100%; + transform: translateY(-50%); + margin-left: calc(var(--spacing) * 4); + } + } + .fade_enter { + opacity: 0%; + transition: opacity 200ms ease-in; + } + .fade_enter_active { + opacity: 100%; + } + .fade_exit { + opacity: 100%; + transition: opacity 200ms ease-out; + } + .fade_exit_active { + opacity: 0%; + } +} diff --git a/src/components/Tooltip.tsx b/src/components/Tooltip.tsx new file mode 100644 index 0000000..7c14a9b --- /dev/null +++ b/src/components/Tooltip.tsx @@ -0,0 +1,46 @@ +import cx from 'clsx'; +import { ReactNode, useRef, useState } from 'react'; +import { CSSTransition } from 'react-transition-group'; +import styles from './Tooltip.module.css'; + +interface TooltipProps { + content: ReactNode; + position?: 'top' | 'bottom' | 'left' | 'right'; + children?: ReactNode; +} + +const positionMap = { + top: styles.top, + bottom: styles.bottom, + left: styles.left, + right: styles.right, +}; + +export function Tooltip({ content, position = 'top', children }: TooltipProps) { + const [show, setShow] = useState(false); + const contentRef = useRef(); + + return ( +
setShow(true)} + onMouseLeave={() => setShow(false)}> + {children} + +
+ {content} +
+
+
+ ); +}