import { BubbleMenu as BaseBubbleMenu, findParentNode, posToDOMRect, } from "@tiptap/react"; import React, { useCallback } from "react"; import { Node as PMNode } from "prosemirror-model"; import { EditorMenuProps, ShouldShowProps, } from "@/features/editor/components/table/types/types.ts"; import { ActionIcon, Tooltip, Divider } from "@mantine/core"; import { IconAlertTriangleFilled, IconCircleCheckFilled, IconCircleXFilled, IconInfoCircleFilled, IconMoodSmile, } from "@tabler/icons-react"; import { CalloutType } from "@docmost/editor-ext"; import { useTranslation } from "react-i18next"; import EmojiPicker from "@/components/ui/emoji-picker.tsx"; export function CalloutMenu({ editor }: EditorMenuProps) { const { t } = useTranslation(); const shouldShow = useCallback( ({ state }: ShouldShowProps) => { if (!state) { return false; } return editor.isActive("callout"); }, [editor], ); const getReferenceClientRect = useCallback(() => { const { selection } = editor.state; const predicate = (node: PMNode) => node.type.name === "callout"; const parent = findParentNode(predicate)(selection); if (parent) { const dom = editor.view.nodeDOM(parent?.pos) as HTMLElement; return dom.getBoundingClientRect(); } return posToDOMRect(editor.view, selection.from, selection.to); }, [editor]); const setCalloutType = useCallback( (calloutType: CalloutType) => { editor .chain() .focus(undefined, { scrollIntoView: false }) .updateCalloutType(calloutType) .run(); }, [editor], ); const setCalloutIcon = useCallback( (emoji: any) => { const emojiChar = emoji?.native || emoji?.emoji || emoji; editor .chain() .focus(undefined, { scrollIntoView: false }) .updateCalloutIcon(emojiChar) .run(); }, [editor], ); const removeCalloutIcon = useCallback(() => { editor .chain() .focus(undefined, { scrollIntoView: false }) .updateCalloutIcon("") .run(); }, [editor]); const getCurrentIcon = () => { const { selection } = editor.state; const predicate = (node: PMNode) => node.type.name === "callout"; const parent = findParentNode(predicate)(selection); const icon = parent?.node.attrs.icon; return icon || null; }; const currentIcon = getCurrentIcon(); return ( setCalloutType("info")} size="lg" aria-label={t("Info")} variant={ editor.isActive("callout", { type: "info" }) ? "light" : "default" } > setCalloutType("success")} size="lg" aria-label={t("Success")} variant={ editor.isActive("callout", { type: "success" }) ? "light" : "default" } > setCalloutType("warning")} size="lg" aria-label={t("Warning")} variant={ editor.isActive("callout", { type: "warning" }) ? "light" : "default" } > setCalloutType("danger")} size="lg" aria-label={t("Danger")} variant={ editor.isActive("callout", { type: "danger" }) ? "light" : "default" } > } actionIconProps={{ size: "lg", variant: "default", c: undefined, }} /> ); } export default CalloutMenu;