diff options
| author | Sam Nystrom <sam@samnystrom.dev> | 2024-03-13 18:01:48 +0000 |
|---|---|---|
| committer | Sam Nystrom <sam@samnystrom.dev> | 2024-03-13 20:17:07 -0400 |
| commit | 9eb1625ec5de3c221ed0445dde874fcb1dc3ff48 (patch) | |
| tree | fe2d2cb383813ca3511af68065257b6ea561afe8 /src/components/ButtonMenu.tsx | |
| parent | 13451b7588aa5800f0c1a87e7c3b49830d9e4087 (diff) | |
feat: add menu components
Diffstat (limited to 'src/components/ButtonMenu.tsx')
| -rw-r--r-- | src/components/ButtonMenu.tsx | 42 |
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; |
