'use client'; import { createPortal } from 'react-dom'; import { useLayoutEffect, useRef, useState, type MouseEvent, type ReactNode } from 'react'; import { BringToFront, SendToBack, Trash2 } from 'lucide-react'; import type { PPTElement } from '@openmaic/dsl'; import { computeToolbarPosition } from '../text/TextToolbarOverlay'; import { useToolbarAnchor } from '../text/useToolbarAnchor'; import type { ElementToolbarLabels } from '../types'; export interface ElementToolbarOverlayProps { readonly element: PPTElement; readonly elementIdPrefix?: string; readonly labels: ElementToolbarLabels; readonly onBringToFront?: () => void; readonly onSendToBack?: () => void; readonly onDelete?: () => void; readonly leading?: ReactNode; } export function ElementToolbarOverlay({ element, elementIdPrefix = 'slide-element-', labels, onBringToFront, onSendToBack, onDelete, leading, }: ElementToolbarOverlayProps) { const anchor = useToolbarAnchor(element.id, elementIdPrefix); const ref = useRef(null); const [size, setSize] = useState<{ width: number; height: number } | null>(null); const preventFocusLoss = (event: MouseEvent) => event.preventDefault(); useLayoutEffect(() => { const toolbar = ref.current; if (!anchor || !toolbar) return; const measure = () => { const rect = toolbar.getBoundingClientRect(); if (rect.width && rect.height) setSize({ width: rect.width, height: rect.height }); }; measure(); const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure); observer?.observe(toolbar); return () => observer?.disconnect(); }, [anchor]); if (!anchor || typeof document === 'undefined') return null; const position = size ? computeToolbarPosition( anchor, size, { width: window.innerWidth, height: window.innerHeight }, 'top', ) : null; return createPortal(
{leading} {leading && (onBringToFront || onSendToBack || onDelete) ? (
, document.body, ); }