diff --git a/src/components/buttons/unselect/unselect.tsx b/src/components/buttons/unselect/unselect.tsx
index 0a2a37e..2671585 100644
--- a/src/components/buttons/unselect/unselect.tsx
+++ b/src/components/buttons/unselect/unselect.tsx
@@ -1,19 +1,8 @@
-import { useState } from 'react';
import { BiUndo, BiTrash } from 'react-icons/bi/index';
-import {
- useFloating,
- autoUpdate,
- offset,
- flip,
- shift,
- useHover,
- useFocus,
- useDismiss,
- useRole,
- useInteractions,
-} from '@floating-ui/react';
import { AnimatePresence, motion } from 'framer-motion';
+import { Tooltip } from '@/components/tooltip';
+
import { useSoundStore } from '@/store';
import { cn } from '@/helpers/styles';
import { fade, mix, slideX } from '@/lib/motion';
@@ -21,28 +10,6 @@ import { fade, mix, slideX } from '@/lib/motion';
import styles from './unselect.module.css';
export function UnselectButton() {
- const [isTooltipOpen, setIsTooltipOpen] = useState(false);
-
- const { context, floatingStyles, refs } = useFloating({
- middleware: [offset(15), flip(), shift()],
- onOpenChange: setIsTooltipOpen,
- open: isTooltipOpen,
- placement: 'top',
- whileElementsMounted: autoUpdate,
- });
-
- const hover = useHover(context, { move: false });
- const focus = useFocus(context);
- const dismiss = useDismiss(context);
- const role = useRole(context, { role: 'tooltip' });
-
- const { getFloatingProps, getReferenceProps } = useInteractions([
- hover,
- focus,
- dismiss,
- role,
- ]);
-
const noSelected = useSoundStore(state => state.noSelected());
const restoreHistory = useSoundStore(state => state.restoreHistory);
const hasHistory = useSoundStore(state => !!state.history);
@@ -60,38 +27,36 @@ export function UnselectButton() {
initial="hidden"
variants={variants}
>
-
+
+
)}
-
- {isTooltipOpen && (
-
- {hasHistory ? 'Restore unselected sounds.' : 'Unselect all sounds.'}
-
- )}
>
);
}
diff --git a/src/components/tooltip/index.ts b/src/components/tooltip/index.ts
new file mode 100644
index 0000000..c20c22c
--- /dev/null
+++ b/src/components/tooltip/index.ts
@@ -0,0 +1 @@
+export { Tooltip } from './tooltip';
diff --git a/src/components/tooltip/tooltip.module.css b/src/components/tooltip/tooltip.module.css
new file mode 100644
index 0000000..e319e38
--- /dev/null
+++ b/src/components/tooltip/tooltip.module.css
@@ -0,0 +1,8 @@
+.tooltip {
+ width: max-content;
+ padding: 6px 12px;
+ border: 1px solid var(--color-neutral-200);
+ border-radius: 100px;
+ background-color: var(--color-neutral-100);
+ font-size: var(--font-xsm);
+}
diff --git a/src/components/tooltip/tooltip.tsx b/src/components/tooltip/tooltip.tsx
new file mode 100644
index 0000000..87c4324
--- /dev/null
+++ b/src/components/tooltip/tooltip.tsx
@@ -0,0 +1,111 @@
+import { useState, cloneElement } from 'react';
+import {
+ useFloating,
+ autoUpdate,
+ offset,
+ flip,
+ shift,
+ useHover,
+ useFocus,
+ useDismiss,
+ useRole,
+ useInteractions,
+ type Placement,
+} from '@floating-ui/react';
+import { motion, AnimatePresence } from 'framer-motion';
+
+import styles from './tooltip.module.css';
+
+interface TooltipProps {
+ children: JSX.Element;
+ content: React.ReactNode;
+ hideDelay?: number;
+ placement?: Placement;
+ showDelay?: number;
+}
+
+export function Tooltip({
+ children,
+ content,
+ hideDelay = 100,
+ placement = 'top',
+ showDelay = 500,
+}: TooltipProps) {
+ const [isTooltipOpen, setIsTooltipOpen] = useState(false);
+
+ const {
+ context,
+ floatingStyles,
+ placement: computedPlacement,
+ refs,
+ strategy,
+ x,
+ y,
+ } = useFloating({
+ middleware: [offset(12), flip(), shift()],
+ onOpenChange: setIsTooltipOpen,
+ open: isTooltipOpen,
+ placement: placement,
+ whileElementsMounted: autoUpdate,
+ });
+
+ const hover = useHover(context, {
+ delay: showDelay,
+ move: false,
+ restMs: hideDelay,
+ });
+ const focus = useFocus(context);
+ const dismiss = useDismiss(context);
+ const role = useRole(context, { role: 'tooltip' });
+
+ const { getFloatingProps, getReferenceProps } = useInteractions([
+ hover,
+ focus,
+ dismiss,
+ role,
+ ]);
+
+ const translate = {
+ bottom: { translateY: -5 },
+ left: { translateX: 5 },
+ right: { translateX: -5 },
+ top: { translateY: 5 },
+ }[
+ computedPlacement.includes('-')
+ ? computedPlacement.split('-')[0]
+ : computedPlacement
+ ];
+
+ const variants = {
+ hidden: { opacity: 0, ...translate },
+ show: { opacity: 1, translateX: 0, translateY: 0 },
+ };
+
+ return (
+ <>
+ {cloneElement(
+ children,
+ getReferenceProps({ ref: refs.setReference, ...children.props }),
+ )}
+
+
+ {isTooltipOpen && (
+
+ {content}
+
+ )}
+
+ >
+ );
+}
diff --git a/src/lib/motion.ts b/src/lib/motion.ts
index b1cd2e3..baf3d6b 100644
--- a/src/lib/motion.ts
+++ b/src/lib/motion.ts
@@ -30,8 +30,8 @@ export function slideX(from = -10, to = 0): Motion {
export function slideY(from = -10, to = 0): Motion {
return {
- hidden: { Y: from },
- show: { Y: to },
+ hidden: { y: from },
+ show: { y: to },
};
}