microeditor: hide on blur
This commit is contained in:
parent
7e6ef23bd2
commit
d485314b11
|
@ -1,8 +1,8 @@
|
|||
import BubbleMenu from '@tiptap/extension-bubble-menu'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
import clsx from 'clsx'
|
||||
import { type JSX, createEffect, createSignal, on } from 'solid-js'
|
||||
import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
|
||||
import { type JSX, createEffect, createSignal, on, onCleanup, onMount } from 'solid-js'
|
||||
import { createEditorTransaction, createTiptapEditor, useEditorHTML } from 'solid-tiptap'
|
||||
import { minimal } from '~/lib/editorExtensions'
|
||||
import { MicroBubbleMenu } from './Toolbar/MicroBubbleMenu'
|
||||
|
||||
|
@ -12,13 +12,18 @@ interface MicroEditorProps {
|
|||
content?: string
|
||||
onChange?: (content: string) => void
|
||||
onSubmit?: (content: string) => void
|
||||
onBlur?: () => void
|
||||
placeholder?: string
|
||||
bordered?: boolean
|
||||
shownAsLead?: boolean
|
||||
focusOnMount?: boolean
|
||||
}
|
||||
|
||||
export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
||||
const [editorElement, setEditorElement] = createSignal<HTMLDivElement>()
|
||||
const [bubbleMenuElement, setBubbleMenuElement] = createSignal<HTMLDivElement>()
|
||||
const [isBlurred, setIsBlurred] = createSignal(false)
|
||||
let blurTimer: number | undefined
|
||||
|
||||
const editor = createTiptapEditor(() => ({
|
||||
element: editorElement()!,
|
||||
|
@ -40,9 +45,54 @@ export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
|||
}))
|
||||
|
||||
const html = useEditorHTML(editor)
|
||||
|
||||
createEffect(on(html, (c?: string) => c && props.onChange?.(c)))
|
||||
|
||||
const lostFocusEmpty = createEditorTransaction(
|
||||
editor,
|
||||
(e) => e && !e.isFocused && e?.view.state.doc.textContent.trim() === ''
|
||||
)
|
||||
createEffect(
|
||||
on(
|
||||
isBlurred,
|
||||
(lost?: boolean) => {
|
||||
if (lost && props.shownAsLead && props.onBlur) {
|
||||
setTimeout(props.onBlur, 1000)
|
||||
}
|
||||
},
|
||||
{ defer: true }
|
||||
)
|
||||
)
|
||||
const handleBlur = () => {
|
||||
blurTimer = window.setTimeout(() => {
|
||||
const isEmpty = editor()?.view.state.doc.textContent.trim() === ''
|
||||
if (isEmpty && props.shownAsLead && props.onBlur) {
|
||||
props.onBlur()
|
||||
}
|
||||
setIsBlurred(true)
|
||||
}, 100) // небольшая задержка для обработки кликов внутри редактора
|
||||
}
|
||||
|
||||
const handleFocus = () => {
|
||||
clearTimeout(blurTimer)
|
||||
setIsBlurred(false)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const editorInstance = editor()
|
||||
if (editorInstance) {
|
||||
editorInstance.on('blur', handleBlur)
|
||||
editorInstance.on('focus', handleFocus)
|
||||
}
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
clearTimeout(blurTimer)
|
||||
editor()?.off('blur', handleBlur)
|
||||
editor()?.off('focus', handleFocus)
|
||||
})
|
||||
|
||||
onMount(() => props.focusOnMount && editor()?.commands.focus())
|
||||
|
||||
return (
|
||||
<div
|
||||
class={clsx(styles.MiniEditor, {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { clsx } from 'clsx'
|
||||
import deepEqual from 'fast-deep-equal'
|
||||
import { Show, createEffect, createSignal, lazy, on, onCleanup, onMount } from 'solid-js'
|
||||
import { Show, createEffect, createSignal, on, onCleanup, onMount } from 'solid-js'
|
||||
import { createStore } from 'solid-js/store'
|
||||
import { debounce } from 'throttle-debounce'
|
||||
import { EditorComponent } from '~/components/Editor/Editor'
|
||||
|
@ -22,16 +22,15 @@ import { LayoutType } from '~/types/common'
|
|||
import { MediaItem } from '~/types/mediaitem'
|
||||
import { clone } from '~/utils/clone'
|
||||
import { AutoSaveNotice } from '../Editor/AutoSaveNotice'
|
||||
import { Panel } from '../Editor/Panel/Panel'
|
||||
import { AudioUploader } from '../Upload/AudioUploader'
|
||||
import { VideoUploader } from '../Upload/VideoUploader'
|
||||
import { Modal } from '../_shared/Modal'
|
||||
import { TableOfContents } from '../_shared/TableOfContents'
|
||||
|
||||
import styles from '~/styles/views/EditView.module.scss'
|
||||
import { Panel } from '../Editor/Panel/Panel'
|
||||
|
||||
const MicroEditor = lazy(() => import('../Editor/MicroEditor'))
|
||||
const GrowingTextarea = lazy(() => import('~/components/_shared/GrowingTextarea/GrowingTextarea'))
|
||||
import MicroEditor from '../Editor/MicroEditor'
|
||||
import GrowingTextarea from '../_shared/GrowingTextarea/GrowingTextarea'
|
||||
|
||||
type Props = {
|
||||
shout: Shout
|
||||
|
@ -63,8 +62,7 @@ export const EditView = (props: Props) => {
|
|||
setFormErrors,
|
||||
saveDraft,
|
||||
saveDraftToLocalStorage,
|
||||
getDraftFromLocalStorage,
|
||||
isCollabMode
|
||||
getDraftFromLocalStorage
|
||||
} = useEditorContext()
|
||||
|
||||
const [subtitleInput, setSubtitleInput] = createSignal<HTMLTextAreaElement | undefined>()
|
||||
|
@ -266,6 +264,10 @@ export const EditView = (props: Props) => {
|
|||
setIsLeadVisible(true)
|
||||
}
|
||||
|
||||
const hideLeadInput = () => {
|
||||
setIsLeadVisible(false)
|
||||
}
|
||||
|
||||
const HeadingActions = () => {
|
||||
return (
|
||||
<div class="col-md-19 col-lg-18 col-xl-16 offset-md-5">
|
||||
|
@ -340,8 +342,10 @@ export const EditView = (props: Props) => {
|
|||
</Show>
|
||||
<Show when={isLeadVisible()}>
|
||||
<MicroEditor
|
||||
shownAsLead={isLeadVisible()}
|
||||
placeholder={t('A short introduction to keep the reader interested')}
|
||||
content={form.lead}
|
||||
onBlur={hideLeadInput}
|
||||
onChange={(value: string) => handleInputChange('lead', value)}
|
||||
/>
|
||||
</Show>
|
||||
|
@ -455,7 +459,6 @@ export const EditView = (props: Props) => {
|
|||
shoutId={form.shoutId}
|
||||
initialContent={form.body}
|
||||
onChange={(body: string) => handleInputChange('body', body)}
|
||||
disableCollaboration={!isCollabMode()}
|
||||
/>
|
||||
<Show when={draft()?.id}>
|
||||
<Panel shoutId={draft()?.id} />
|
||||
|
|
Loading…
Reference in New Issue
Block a user