Feature/refactoring simplyfy editor (#318)

add Linkbubble menu
This commit is contained in:
Ilya Y 2023-11-15 17:52:10 +03:00 committed by GitHub
parent ed85b75cc8
commit 8b114ea75f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 13 deletions

View File

@ -0,0 +1,4 @@
.LinkBubbleMenu {
background: var(--editor-bubble-menu-background);
box-shadow: 0 4px 10px rgba(#000, 0.25);
}

View File

@ -0,0 +1,20 @@
import type { Editor } from '@tiptap/core'
import { InsertLinkForm } from '../InsertLinkForm'
import styles from './LinkBubbleMenu.module.scss'
type Props = {
editor: Editor
ref: (el: HTMLDivElement) => void
shouldShow: boolean
onClose: () => void
}
export const LinkBubbleMenuModule = (props: Props) => {
return (
<div ref={props.ref} class={styles.LinkBubbleMenu}>
<InsertLinkForm editor={props.editor} onClose={props.onClose} />
</div>
)
}

View File

@ -0,0 +1 @@
export { LinkBubbleMenuModule } from './LinkBubbleMenu.module'

View File

@ -31,7 +31,7 @@ import { Modal } from '../Nav/Modal'
import { Figcaption } from './extensions/Figcaption' import { Figcaption } from './extensions/Figcaption'
import { Figure } from './extensions/Figure' import { Figure } from './extensions/Figure'
import { InsertLinkForm } from './InsertLinkForm' import { LinkBubbleMenuModule } from './LinkBubbleMenu'
import { TextBubbleMenu } from './TextBubbleMenu' import { TextBubbleMenu } from './TextBubbleMenu'
import { UploadModalContent } from './UploadModalContent' import { UploadModalContent } from './UploadModalContent'
@ -64,7 +64,7 @@ export const MAX_DESCRIPTION_LIMIT = 400
const SimplifiedEditor = (props: Props) => { const SimplifiedEditor = (props: Props) => {
const { t } = useLocalize() const { t } = useLocalize()
const [counter, setCounter] = createSignal<number>() const [counter, setCounter] = createSignal<number>()
const [shouldShowLinkBubbleMenu, setShouldShowLinkBubbleMenu] = createSignal(false)
const isCancelButtonVisible = createMemo(() => props.isCancelButtonVisible !== false) const isCancelButtonVisible = createMemo(() => props.isCancelButtonVisible !== false)
const wrapperEditorElRef: { const wrapperEditorElRef: {
current: HTMLElement current: HTMLElement
@ -84,6 +84,12 @@ const SimplifiedEditor = (props: Props) => {
current: null, current: null,
} }
const linkBubbleMenuRef: {
current: HTMLDivElement
} = {
current: null,
}
const { const {
actions: { setEditor }, actions: { setEditor },
} = useEditorContext() } = useEditorContext()
@ -129,6 +135,15 @@ const SimplifiedEditor = (props: Props) => {
return view.hasFocus() && !empty return view.hasFocus() && !empty
}, },
}), }),
BubbleMenu.configure({
pluginKey: 'linkBubbleMenu',
element: linkBubbleMenuRef.current,
shouldShow: ({ state }) => {
const { selection } = state
const { empty } = selection
return !empty && shouldShowLinkBubbleMenu()
},
}),
ImageFigure, ImageFigure,
Image, Image,
Figcaption, Figcaption,
@ -213,7 +228,7 @@ const SimplifiedEditor = (props: Props) => {
if (event.code === 'KeyK' && (event.metaKey || event.ctrlKey) && !editor().state.selection.empty) { if (event.code === 'KeyK' && (event.metaKey || event.ctrlKey) && !editor().state.selection.empty) {
event.preventDefault() event.preventDefault()
showModal('simplifiedEditorInsertLink') setShouldShowLinkBubbleMenu(true)
} }
} }
@ -231,8 +246,6 @@ const SimplifiedEditor = (props: Props) => {
}) })
} }
const handleInsertLink = () => !editor().state.selection.empty && showModal('simplifiedEditorInsertLink')
createEffect(() => { createEffect(() => {
if (html()) { if (html()) {
setCounter(editor().storage.characterCount.characters()) setCounter(editor().storage.characterCount.characters())
@ -244,6 +257,10 @@ const SimplifiedEditor = (props: Props) => {
'max-height': `${props.maxHeight}px`, 'max-height': `${props.maxHeight}px`,
} }
const handleShowLinkBubble = () => {
editor().chain().focus().run()
setShouldShowLinkBubbleMenu(true)
}
return ( return (
<div <div
ref={(el) => (wrapperEditorElRef.current = el)} ref={(el) => (wrapperEditorElRef.current = el)}
@ -294,7 +311,7 @@ const SimplifiedEditor = (props: Props) => {
<button <button
ref={triggerRef} ref={triggerRef}
type="button" type="button"
onClick={handleInsertLink} onClick={handleShowLinkBubble}
class={clsx(styles.actionButton, { [styles.active]: isLink() })} class={clsx(styles.actionButton, { [styles.active]: isLink() })}
> >
<Icon name="editor-link" /> <Icon name="editor-link" />
@ -345,11 +362,6 @@ const SimplifiedEditor = (props: Props) => {
</Show> </Show>
</div> </div>
</Show> </Show>
<Portal>
<Modal variant="narrow" name="simplifiedEditorInsertLink">
<InsertLinkForm editor={editor()} onClose={() => hideModal()} />
</Modal>
</Portal>
<Show when={props.imageEnabled}> <Show when={props.imageEnabled}>
<Portal> <Portal>
<Modal variant="narrow" name="simplifiedEditorUploadImage"> <Modal variant="narrow" name="simplifiedEditorUploadImage">
@ -369,6 +381,12 @@ const SimplifiedEditor = (props: Props) => {
ref={(el) => (textBubbleMenuRef.current = el)} ref={(el) => (textBubbleMenuRef.current = el)}
/> />
</Show> </Show>
<LinkBubbleMenuModule
shouldShow={shouldShowLinkBubbleMenu()}
editor={editor()}
ref={(el) => (linkBubbleMenuRef.current = el)}
onClose={() => setShouldShowLinkBubbleMenu(false)}
/>
</div> </div>
) )
} }

View File

@ -21,7 +21,6 @@ export type ModalType =
| 'simplifiedEditorUploadImage' | 'simplifiedEditorUploadImage'
| 'uploadCoverImage' | 'uploadCoverImage'
| 'editorInsertLink' | 'editorInsertLink'
| 'simplifiedEditorInsertLink'
| 'followers' | 'followers'
| 'following' | 'following'
@ -37,7 +36,6 @@ export const MODALS: Record<ModalType, ModalType> = {
simplifiedEditorUploadImage: 'simplifiedEditorUploadImage', simplifiedEditorUploadImage: 'simplifiedEditorUploadImage',
uploadCoverImage: 'uploadCoverImage', uploadCoverImage: 'uploadCoverImage',
editorInsertLink: 'editorInsertLink', editorInsertLink: 'editorInsertLink',
simplifiedEditorInsertLink: 'simplifiedEditorInsertLink',
followers: 'followers', followers: 'followers',
following: 'following', following: 'following',
} }