"use client" import * as React from "react" import { Separator } from "@/components/tiptap-ui-primitive/separator" import "@/components/tiptap-ui-primitive/toolbar/toolbar.scss" import { cn } from "@/lib/tiptap-utils" import { useMenuNavigation } from "@/hooks/use-menu-navigation" import { useComposedRef } from "@/hooks/use-composed-ref" type BaseProps = React.HTMLAttributes interface ToolbarProps extends BaseProps { variant?: "floating" | "fixed" } const useToolbarNavigation = ( toolbarRef: React.RefObject ) => { const [items, setItems] = React.useState([]) const collectItems = React.useCallback(() => { if (!toolbarRef.current) return [] return Array.from( toolbarRef.current.querySelectorAll( 'button:not([disabled]), [role="button"]:not([disabled]), [tabindex="0"]:not([disabled])' ) ) }, [toolbarRef]) React.useEffect(() => { const toolbar = toolbarRef.current if (!toolbar) return const updateItems = () => setItems(collectItems()) updateItems() const observer = new MutationObserver(updateItems) observer.observe(toolbar, { childList: true, subtree: true }) return () => observer.disconnect() }, [collectItems, toolbarRef]) const { selectedIndex } = useMenuNavigation({ containerRef: toolbarRef, items, orientation: "horizontal", onSelect: (el) => el.click(), autoSelectFirstItem: false, }) React.useEffect(() => { const toolbar = toolbarRef.current if (!toolbar) return const handleFocus = (e: FocusEvent) => { const target = e.target as HTMLElement if (toolbar.contains(target)) target.setAttribute("data-focus-visible", "true") } const handleBlur = (e: FocusEvent) => { const target = e.target as HTMLElement if (toolbar.contains(target)) target.removeAttribute("data-focus-visible") } toolbar.addEventListener("focus", handleFocus, true) toolbar.addEventListener("blur", handleBlur, true) return () => { toolbar.removeEventListener("focus", handleFocus, true) toolbar.removeEventListener("blur", handleBlur, true) } }, [toolbarRef]) React.useEffect(() => { if (selectedIndex !== undefined && items[selectedIndex]) { items[selectedIndex].focus() } }, [selectedIndex, items]) } export const Toolbar = React.forwardRef( ({ children, className, variant = "fixed", ...props }, ref) => { const toolbarRef = React.useRef(null) const composedRef = useComposedRef(toolbarRef, ref) useToolbarNavigation(toolbarRef) return (
{children}
) } ) Toolbar.displayName = "Toolbar" export const ToolbarGroup = React.forwardRef( ({ children, className, ...props }, ref) => (
{children}
) ) ToolbarGroup.displayName = "ToolbarGroup" export const ToolbarSeparator = React.forwardRef( ({ ...props }, ref) => ( ) ) ToolbarSeparator.displayName = "ToolbarSeparator"