Files
GibSend/packages/email-editor/src/menus/LinkMenu.tsx
2025-09-26 14:30:57 -05:00

82 lines
2.0 KiB
TypeScript

import { BubbleMenu as BaseBubbleMenu } from '@tiptap/react';
import React, { useCallback, useState } from 'react';
import { MenuProps } from '../types';
import { LinkPreviewPanel } from '../components/panels/LinkPreviewPanel';
import { LinkEditorPanel } from '../components/panels/LinkEditorPanel';
export const LinkMenu = ({ editor, appendTo }: MenuProps): React.ReactNode => {
const [showEdit, setShowEdit] = useState(false);
const shouldShow = useCallback(() => {
const isActive = editor.isActive('link');
return isActive;
}, [editor]);
const { href: link } = editor.getAttributes('link');
const handleEdit = useCallback(() => {
setShowEdit(true);
}, []);
const onSetLink = useCallback(
(url: string) => {
editor
.chain()
.focus()
.extendMarkRange('link')
.setLink({ href: url, target: '_blank' })
.run();
setShowEdit(false);
},
[editor],
);
const onUnsetLink = useCallback(() => {
editor.chain().focus().extendMarkRange('link').unsetLink().run();
setShowEdit(false);
return null;
}, [editor]);
const onShowEdit = useCallback(() => {
setShowEdit(true);
}, []);
const onHideEdit = useCallback(() => {
setShowEdit(false);
}, []);
return (
<BaseBubbleMenu
editor={editor}
pluginKey="textMenu"
shouldShow={shouldShow}
updateDelay={0}
tippyOptions={{
popperOptions: {
modifiers: [{ name: 'flip', enabled: false }],
},
appendTo: () => {
return appendTo?.current;
},
onHidden: () => {
setShowEdit(false);
},
}}
className="mt-4 flex items-center gap-1 rounded-md border border-gray-200 bg-white p-1 shadow-md"
>
{showEdit ? (
<LinkEditorPanel initialUrl={link} onSetLink={onSetLink} />
) : (
<LinkPreviewPanel
url={link}
onClear={onUnsetLink}
onEdit={handleEdit}
/>
)}
</BaseBubbleMenu>
);
};
export default LinkMenu;