microeditor: hide on blur
All checks were successful
deploy / testbuild (push) Successful in 2m13s
deploy / Update templates on Mailgun (push) Has been skipped

This commit is contained in:
Untone 2024-10-11 05:26:14 +03:00
parent 7e6ef23bd2
commit d485314b11
2 changed files with 64 additions and 11 deletions

View File

@ -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, {

View File

@ -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} />