summaryrefslogtreecommitdiff
path: root/src/components/ButtonMenu.tsx
diff options
context:
space:
mode:
authorSam Nystrom <sam@samnystrom.dev>2024-03-13 18:01:48 +0000
committerSam Nystrom <sam@samnystrom.dev>2024-03-13 20:17:07 -0400
commit9eb1625ec5de3c221ed0445dde874fcb1dc3ff48 (patch)
treefe2d2cb383813ca3511af68065257b6ea561afe8 /src/components/ButtonMenu.tsx
parent13451b7588aa5800f0c1a87e7c3b49830d9e4087 (diff)
feat: add menu components
Diffstat (limited to 'src/components/ButtonMenu.tsx')
-rw-r--r--src/components/ButtonMenu.tsx42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/components/ButtonMenu.tsx b/src/components/ButtonMenu.tsx
new file mode 100644
index 0000000..6a2b73e
--- /dev/null
+++ b/src/components/ButtonMenu.tsx
@@ -0,0 +1,42 @@
+import type { ComponentChildren } from 'preact';
+import { useEffect, useRef, useId } from 'preact/hooks';
+import { useSignal, batch } from '@preact/signals';
+import Button from './Button.tsx';
+import Menu from './Menu.tsx';
+import './ButtonMenu.css';
+
+export interface ButtonMenuProps {
+ children: ComponentChildren;
+ label: string;
+}
+
+const ButtonMenu = ({ children, label }: ButtonMenuProps) => {
+ const id = useId();
+ const ref = useRef(null);
+ const x = useSignal(0);
+ const y = useSignal(0);
+
+ const updateRect = () => batch(() => {
+ const rect = ref.current?.getBoundingClientRect();
+ if (!rect) return;
+ x.value = rect.x;
+ y.value = rect.y + rect.height + 1;
+ });
+ useEffect(updateRect, [ref.current]);
+
+ return (
+ <div
+ class="__ButtonMenu"
+ ref={ref}
+ onScroll={updateRect}
+ style={`--anchor-x: ${x}px; --anchor-y: ${y}px;`}
+ >
+ <Button kind="ghost" popoverTarget={id}>{label}</Button>
+ <Menu id={id} popover="auto">
+ {children}
+ </Menu>
+ </div>
+ );
+};
+
+export default ButtonMenu;