refactoring and minimize
This commit is contained in:
parent
87f66d83b6
commit
102ad86b59
|
@ -1,4 +1,4 @@
|
||||||
import { createEffect, createSignal, Show } from 'solid-js'
|
import { Match, Switch, createSignal, Show } from 'solid-js'
|
||||||
import type { Editor } from '@tiptap/core'
|
import type { Editor } from '@tiptap/core'
|
||||||
import styles from './EditorBubbleMenu.module.scss'
|
import styles from './EditorBubbleMenu.module.scss'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
|
@ -7,8 +7,6 @@ import { createEditorTransaction } from 'solid-tiptap'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '../../context/localize'
|
||||||
import validateUrl from '../../utils/validateUrl'
|
import validateUrl from '../../utils/validateUrl'
|
||||||
|
|
||||||
type HeadingLevel = 1 | 2 | 3
|
|
||||||
type ActionName = 'heading' | 'bold' | 'italic' | 'blockquote' | 'isOrderedList' | 'isBulletList'
|
|
||||||
type BubbleMenuProps = {
|
type BubbleMenuProps = {
|
||||||
editor: Editor
|
editor: Editor
|
||||||
ref: (el: HTMLDivElement) => void
|
ref: (el: HTMLDivElement) => void
|
||||||
|
@ -23,21 +21,27 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
const [prevUrl, setPrevUrl] = createSignal<string | null>(null)
|
const [prevUrl, setPrevUrl] = createSignal<string | null>(null)
|
||||||
const [linkError, setLinkError] = createSignal<string | null>(null)
|
const [linkError, setLinkError] = createSignal<string | null>(null)
|
||||||
|
|
||||||
const activeControl = (action: ActionName, actionLevel?: HeadingLevel, prevLink?: boolean) =>
|
const isActive = (name: string, attributes?: {}, checkPrevUrl?: boolean) =>
|
||||||
createEditorTransaction(
|
createEditorTransaction(
|
||||||
() => props.editor,
|
|
||||||
(editor) => editor && editor.isActive(action, actionLevel && { actionLevel })
|
|
||||||
)
|
|
||||||
|
|
||||||
const isLink = createEditorTransaction(
|
|
||||||
// вызов этой ф-ии обусловлен не через хэлпер activeControl только проверкой установленна ли ссылка
|
|
||||||
() => props.editor,
|
() => props.editor,
|
||||||
(editor) => {
|
(editor) => {
|
||||||
editor && editor.isActive('link')
|
editor && editor.isActive(name, attributes)
|
||||||
|
if (checkPrevUrl) {
|
||||||
setPrevUrl(editor && editor.getAttributes('link').href)
|
setPrevUrl(editor && editor.getAttributes('link').href)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const isBold = isActive('bold')
|
||||||
|
const isItalic = isActive('italic')
|
||||||
|
const isH1 = isActive('heading', { level: 1 })
|
||||||
|
const isH2 = isActive('heading', { level: 2 })
|
||||||
|
const isH3 = isActive('heading', { level: 3 })
|
||||||
|
const isBlockQuote = isActive('blockquote')
|
||||||
|
const isOrderedList = isActive('isOrderedList')
|
||||||
|
const isBulletList = isActive('isBulletList')
|
||||||
|
const isLink = isActive('link', {}, true)
|
||||||
|
|
||||||
const clearLinkForm = () => {
|
const clearLinkForm = () => {
|
||||||
setUrl('')
|
setUrl('')
|
||||||
setLinkEditorOpen(false)
|
setLinkEditorOpen(false)
|
||||||
|
@ -45,8 +49,14 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
|
|
||||||
const handleSubmitLink = (e) => {
|
const handleSubmitLink = (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
if (url().length === 0) {
|
||||||
|
props.editor.chain().focus().unsetLink().run()
|
||||||
|
clearLinkForm()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (url().length > 1 && validateUrl(url())) {
|
if (url().length > 1 && validateUrl(url())) {
|
||||||
props.editor.commands.toggleLink({ href: url() })
|
props.editor.chain().focus().toggleLink({ href: url() }).run()
|
||||||
clearLinkForm()
|
clearLinkForm()
|
||||||
} else {
|
} else {
|
||||||
setLinkError(t('Invalid url format'))
|
setLinkError(t('Invalid url format'))
|
||||||
|
@ -65,7 +75,8 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div ref={props.ref} class={styles.bubbleMenu}>
|
<div ref={props.ref} class={styles.bubbleMenu}>
|
||||||
{linkEditorOpen() ? (
|
<Switch>
|
||||||
|
<Match when={linkEditorOpen()}>
|
||||||
<>
|
<>
|
||||||
<form onSubmit={(e) => handleSubmitLink(e)} class={styles.linkForm}>
|
<form onSubmit={(e) => handleSubmitLink(e)} class={styles.linkForm}>
|
||||||
<input
|
<input
|
||||||
|
@ -84,7 +95,8 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
</form>
|
</form>
|
||||||
{linkError() && <div class={styles.linkError}>{linkError()}</div>}
|
{linkError() && <div class={styles.linkError}>{linkError()}</div>}
|
||||||
</>
|
</>
|
||||||
) : (
|
</Match>
|
||||||
|
<Match when={!linkEditorOpen()}>
|
||||||
<>
|
<>
|
||||||
<div class={styles.dropDownHolder}>
|
<div class={styles.dropDownHolder}>
|
||||||
<button
|
<button
|
||||||
|
@ -104,27 +116,27 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('heading', 1)()
|
[styles.bubbleMenuButtonActive]: isH1()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleHeading({ level: 1 })}
|
onClick={() => props.editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-h1" />
|
<Icon name="editor-h1" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('heading', 2)()
|
[styles.bubbleMenuButtonActive]: isH2()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleHeading({ level: 2 })}
|
onClick={() => props.editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-h2" />
|
<Icon name="editor-h2" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('heading', 3)()
|
[styles.bubbleMenuButtonActive]: isH3()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleHeading({ level: 3 })}
|
onClick={() => props.editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-h3" />
|
<Icon name="editor-h3" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -134,12 +146,21 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('blockquote')()
|
[styles.bubbleMenuButtonActive]: isBlockQuote()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.chain().focus().toggleBlockquote().run()}
|
onClick={() => props.editor.chain().focus().toggleBlockquote().run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-blockquote" />
|
<Icon name="editor-blockquote" />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
|
[styles.bubbleMenuButtonActive]: isBlockQuote()
|
||||||
|
})}
|
||||||
|
onClick={() => props.editor.chain().focus().toggleBlockquote().run()}
|
||||||
|
>
|
||||||
|
<Icon name="editor-quote" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
@ -148,18 +169,18 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('bold')()
|
[styles.bubbleMenuButtonActive]: isBold()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleBold()}
|
onClick={() => props.editor.chain().focus().toggleBold().run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-bold" />
|
<Icon name="editor-bold" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('italic')()
|
[styles.bubbleMenuButtonActive]: isItalic()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleItalic()}
|
onClick={() => props.editor.chain().focus().toggleItalic().run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-italic" />
|
<Icon name="editor-italic" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -175,9 +196,6 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
>
|
>
|
||||||
<Icon name="editor-link" />
|
<Icon name="editor-link" />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class={styles.bubbleMenuButton}>
|
|
||||||
<div class={styles.colorWheel} />
|
|
||||||
</button>
|
|
||||||
<button type="button" class={styles.bubbleMenuButton}>
|
<button type="button" class={styles.bubbleMenuButton}>
|
||||||
<Icon name="editor-footnote" />
|
<Icon name="editor-footnote" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -185,7 +203,9 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
<div class={styles.dropDownHolder}>
|
<div class={styles.dropDownHolder}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, { [styles.bubbleMenuButtonActive]: listBubbleOpen() })}
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
|
[styles.bubbleMenuButtonActive]: listBubbleOpen()
|
||||||
|
})}
|
||||||
onClick={toggleListPopup}
|
onClick={toggleListPopup}
|
||||||
>
|
>
|
||||||
<Icon name="editor-ul" />
|
<Icon name="editor-ul" />
|
||||||
|
@ -198,18 +218,18 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('isBulletList')
|
[styles.bubbleMenuButtonActive]: isBulletList()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleBulletList()}
|
onClick={() => props.editor.chain().focus().toggleBulletList().run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-ul" />
|
<Icon name="editor-ul" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={clsx(styles.bubbleMenuButton, {
|
class={clsx(styles.bubbleMenuButton, {
|
||||||
[styles.bubbleMenuButtonActive]: activeControl('isOrderedList')
|
[styles.bubbleMenuButtonActive]: isOrderedList()
|
||||||
})}
|
})}
|
||||||
onClick={() => props.editor.commands.toggleOrderedList()}
|
onClick={() => props.editor.chain().focus().toggleOrderedList().run()}
|
||||||
>
|
>
|
||||||
<Icon name="editor-ol" />
|
<Icon name="editor-ol" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -218,7 +238,8 @@ export const EditorBubbleMenu = (props: BubbleMenuProps) => {
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
</Match>
|
||||||
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user