From d485314b11c26da5f499212ec627c066b75f6286 Mon Sep 17 00:00:00 2001 From: Untone Date: Fri, 11 Oct 2024 05:26:14 +0300 Subject: [PATCH] microeditor: hide on blur --- src/components/Editor/MicroEditor.tsx | 56 +++++++++++++++++++++++++-- src/components/Views/EditView.tsx | 19 +++++---- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/components/Editor/MicroEditor.tsx b/src/components/Editor/MicroEditor.tsx index 5a27bb59..e22b7c89 100644 --- a/src/components/Editor/MicroEditor.tsx +++ b/src/components/Editor/MicroEditor.tsx @@ -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() const [bubbleMenuElement, setBubbleMenuElement] = createSignal() + 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 (
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() @@ -266,6 +264,10 @@ export const EditView = (props: Props) => { setIsLeadVisible(true) } + const hideLeadInput = () => { + setIsLeadVisible(false) + } + const HeadingActions = () => { return (
@@ -340,8 +342,10 @@ export const EditView = (props: Props) => { handleInputChange('lead', value)} /> @@ -455,7 +459,6 @@ export const EditView = (props: Props) => { shoutId={form.shoutId} initialContent={form.body} onChange={(body: string) => handleInputChange('body', body)} - disableCollaboration={!isCollabMode()} />