import type { Editor } from '@tiptap/core' import type { MenuItem } from './Menu/Menu' import { Show, createEffect, createSignal } from 'solid-js' import { useLocalize } from '../../../context/localize' import { UploadedFile } from '../../../pages/types' import { showModal } from '../../../stores/ui' import { renderUploadedImage } from '../../../utils/renderUploadedImage' import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler' import { Modal } from '../../Nav/Modal' import { Icon } from '../../_shared/Icon' import { InlineForm } from '../InlineForm' import { UploadModalContent } from '../UploadModalContent' import { Menu } from './Menu' import styles from './EditorFloatingMenu.module.scss' type FloatingMenuProps = { editor: Editor ref: (el: HTMLDivElement) => void } const embedData = (data) => { const element = document.createRange().createContextualFragment(data) const { attributes } = element.firstChild as HTMLIFrameElement const result: { src: string; width?: string; height?: string } = { src: '' } for (let i = 0; i < attributes.length; i++) { const attribute = attributes.item(i) if (attribute) { result[attribute.name] = attribute.value } } return result } export const EditorFloatingMenu = (props: FloatingMenuProps) => { const { t } = useLocalize() const [selectedMenuItem, setSelectedMenuItem] = createSignal() const [menuOpen, setMenuOpen] = createSignal(false) const menuRef: { current: HTMLDivElement } = { current: null } const plusButtonRef: { current: HTMLButtonElement } = { current: null } const handleEmbedFormSubmit = async (value: string) => { // TODO: add support instagram embed (blockquote) const emb = await embedData(value) props.editor .chain() .focus() .insertContent({ type: 'figure', attrs: { 'data-type': 'iframe' }, content: [ { type: 'iframe', attrs: { src: emb.src, width: emb.width, height: emb.height, }, }, { type: 'figcaption', content: [{ type: 'text', text: t('Description') }], }, ], }) .run() } const validateEmbed = (value) => { const element = document.createRange().createContextualFragment(value) if (element.firstChild?.nodeName !== 'IFRAME') { return t('Error') } } createEffect(() => { switch (selectedMenuItem()) { case 'image': { showModal('uploadImage') return } case 'horizontal-rule': { props.editor.chain().focus().setHorizontalRule().run() setSelectedMenuItem() return } } }) const closeUploadModalHandler = () => { setSelectedMenuItem() setMenuOpen(false) setSelectedMenuItem() } useOutsideClickHandler({ containerRef: menuRef, handler: (e) => { if (plusButtonRef.current.contains(e.target)) { return } if (menuOpen()) { setMenuOpen(false) setSelectedMenuItem() } }, }) const handleUpload = (image: UploadedFile) => { renderUploadedImage(props.editor, image) } return ( <>
(menuRef.current = el)}> setSelectedMenuItem(value)} /> setSelectedMenuItem()} validate={validateEmbed} onSubmit={handleEmbedFormSubmit} />
{ handleUpload(value) setSelectedMenuItem() }} /> ) }