opvault.js/packages/web/src/components/ItemFieldContextMenu.tsx
2021-11-23 03:13:01 -05:00

102 lines
2.0 KiB
TypeScript

import { useCallback, useEffect, useState } from "react"
import styled from "@emotion/styled"
const Container = styled.menu`
background-color: #fff;
border-radius: 3px;
box-shadow: #0004 0px 1px 4px;
left: 99%;
margin-block-start: 0;
min-width: 180px;
padding-inline-start: 0;
position: absolute;
top: 0;
user-select: none;
z-index: 2;
@media (prefers-color-scheme: dark) {
background-color: #3c3c3c;
box-shadow: rgb(0 0 0) 0px 2px 4px;
color: #f0f0f0;
}
& & {
display: none;
}
`
const Separator = styled.div`
border-bottom: 1px solid #777;
margin-top: 0.4em;
margin-bottom: 0.4em;
margin-left: 0.6em;
margin-right: 0.6em;
`
const Item = styled.div`
cursor: default;
font-size: 13px;
flex: 1 1 auto;
display: flex;
height: 2.5em;
align-items: center;
padding-left: 1em;
padding-right: 5px;
position: relative;
&:hover {
background-color: #ddd;
border-radius: 3px;
.item-field-context-menu {
display: block;
}
@media (prefers-color-scheme: dark) {
background-color: #094771;
}
}
`
function useContextMenu() {
const [show, setShow] = useState(false)
const [pos, setPos] = useState({ x: 0, y: 0 })
const onRightClick = useCallback((e: React.MouseEvent) => {
setShow(true)
e.preventDefault()
setPos({ x: e.pageX, y: e.pageY })
}, [])
useEffect(() => {
const fn = () => setShow(false)
document.addEventListener("click", fn)
return () => document.removeEventListener("click", fn)
}, [])
return {
show,
position: {
top: pos.y,
left: pos.x,
},
onRightClick,
}
}
export function useItemFieldContextMenu() {
const { onRightClick, position, show } = useContextMenu()
const ContextMenuContainer: React.FC = useCallback(
({ children }) => {
if (!show) return null
return (
<Container style={position} className="item-field-context-menu">
{children}
</Container>
)
},
[show, position]
)
return {
onRightClick,
Item,
ContextMenuContainer,
}
}