import {
Box,
Flex,
Menu,
MenuDivider,
MenuGroup,
MenuItem,
Popover,
Spinner,
Stack,
Text,
type PopoverMargins,
} from '@sanity/ui/_visual-editing'
import {useCallback, useEffect, useMemo, useState, type FunctionComponent} from 'react'
import type {ContextMenuNode, ContextMenuProps} from '../../types'
import {useDocuments} from '../../react/useDocuments'
import {getNodeIcon} from '../../util/getNodeIcon'
import {PopoverPortal} from '../PopoverPortal'
import {useSchema} from '../schema/useSchema'
import {useTelemetry} from '../telemetry/useTelemetry'
import {getContextMenuItems} from './contextMenuItems'
const POPOVER_MARGINS: PopoverMargins = [-4, 4, -4, 4]
function ContextMenuItem(props: {
node: ContextMenuNode
onDismiss?: () => void
boundaryElement: HTMLDivElement | null
}) {
const {node, onDismiss, boundaryElement} = props
const sendTelemetry = useTelemetry()
const onClick = useCallback(() => {
if (node.type === 'action') {
node.action?.()
onDismiss?.()
if (node.telemetryEvent) {
sendTelemetry(node.telemetryEvent, null)
}
}
}, [node, onDismiss, sendTelemetry])
if (node.type === 'divider') {
return
}
if (node.type === 'action') {
return (
)
}
if (node.type === 'group') {
return (
{node.items.map((item, itemIndex) => (
))}
)
}
if (node.type === 'custom') {
const {component: Component} = node
return
}
return null
}
export const ContextMenu: FunctionComponent = (props) => {
const {
node,
onDismiss,
position: {x, y},
} = props
const [boundaryElement, setBoundaryElement] = useState(null)
const {getField} = useSchema()
const {getDocument} = useDocuments()
const {field, parent} = getField(node)
const title = useMemo(() => {
return field?.title || field?.name || 'Unknown type'
}, [field])
const [items, setItems] = useState(undefined)
useEffect(() => {
const fetchContextMenuItems = async () => {
const doc = getDocument(node.id)
if (!doc) return
const items = await getContextMenuItems({node, field, parent, doc})
setItems(items)
}
fetchContextMenuItems()
}, [field, node, parent, getDocument])
const contextMenuReferenceElement = useMemo(() => {
return {
getBoundingClientRect: () => ({
bottom: y,
left: x,
right: x,
top: y,
width: 0,
height: 0,
}),
} as HTMLElement
}, [x, y])
const icon = useMemo(() => {
return getNodeIcon(field)
}, [field])
return (
{items ? {icon} : }
{items ? title : 'Loading...'}
{items && (
<>
{items.map((item, i) => (
))}
>
)}
}
>
)
}