MiniEditor-fix
This commit is contained in:
parent
962140e755
commit
7aa01d6152
|
@ -8,7 +8,6 @@ import { InlineForm } from '../InlineForm'
|
|||
type Props = {
|
||||
editor: Editor
|
||||
onClose: () => void
|
||||
onFocus: (event: FocusEvent) => void
|
||||
}
|
||||
|
||||
export const checkUrl = (url: string) => {
|
||||
|
@ -62,7 +61,6 @@ export const InsertLinkForm = (props: Props) => {
|
|||
validate={(value) => (validateUrl(value) ? '' : t('Invalid url format'))}
|
||||
onSubmit={handleLinkFormSubmit}
|
||||
onClose={props.onClose}
|
||||
onFocus={props.onFocus}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -63,15 +63,6 @@ export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
|||
const [showLinkInput, setShowLinkInput] = createSignal(false)
|
||||
const [showSimpleMenu, setShowSimpleMenu] = createSignal(false)
|
||||
const [toolbarElement, setToolbarElement] = createSignal<HTMLElement>()
|
||||
const [selectionRange, setSelectionRange] = createSignal<Range | null>(null)
|
||||
|
||||
const handleLinkInputFocus = (event: FocusEvent) => {
|
||||
event.preventDefault()
|
||||
const selection = window.getSelection()
|
||||
if (selection?.rangeCount) {
|
||||
setSelectionRange(selection.getRangeAt(0))
|
||||
}
|
||||
}
|
||||
|
||||
const editor = createTiptapEditor(() => ({
|
||||
element: editorElement()!,
|
||||
|
@ -87,12 +78,32 @@ export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
|||
content: props.content || ''
|
||||
}))
|
||||
|
||||
const selection = createEditorTransaction(editor, (instance) => instance?.state.selection)
|
||||
const [storedSelection, setStoredSelection] = createSignal<Editor['state']['selection']>()
|
||||
const recoverSelection = () => {
|
||||
if (!storedSelection()?.empty) {
|
||||
// TODO set selection range from stored
|
||||
createEditorTransaction(editor, (instance?: Editor) => {
|
||||
const r = selection()
|
||||
if (instance && r) {
|
||||
instance.state.selection.from === r.from
|
||||
instance.state.selection.to === r.to
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const storeSelection = (event: Event) => {
|
||||
event.preventDefault()
|
||||
const selection = editor()?.state.selection
|
||||
if (!selection?.empty) {
|
||||
setStoredSelection(selection)
|
||||
}
|
||||
}
|
||||
|
||||
const isEmpty = useEditorIsEmpty(editor)
|
||||
const isFocused = useEditorIsFocused(editor)
|
||||
const isTextSelection = createEditorTransaction(editor, (instance) => !instance?.state.selection.empty)
|
||||
const html = useEditorHTML(editor)
|
||||
|
||||
createEffect(on([isTextSelection, showLinkInput],([selected, linkEditing]) => !linkEditing && setShowSimpleMenu(selected)))
|
||||
createEffect(on([selection, showLinkInput], ([s, l]) => !l && setShowSimpleMenu(!s?.empty)))
|
||||
createEffect(on(html, (c?: string) => c && props.onChange?.(c)))
|
||||
createEffect(on(showLinkInput, (x?: boolean) => x && editor()?.chain().focus().run()))
|
||||
createReaction(on(toolbarElement, (t?: HTMLElement) => t?.addEventListener('mousedown', prevent)))
|
||||
|
@ -117,19 +128,6 @@ export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
|||
ref={setToolbarElement}
|
||||
>
|
||||
<div class={styles.controls}>
|
||||
<Show
|
||||
when={!showLinkInput()}
|
||||
fallback={<InsertLinkForm editor={instance}
|
||||
onClose={() => {
|
||||
setShowLinkInput(false)
|
||||
if (selectionRange()) {
|
||||
const selection = window.getSelection()
|
||||
selection?.removeAllRanges()
|
||||
selection?.addRange(selectionRange()!)
|
||||
}
|
||||
}}
|
||||
onFocus={handleLinkInputFocus} />}
|
||||
>
|
||||
<div class={styles.actions}>
|
||||
<Control
|
||||
key="bold"
|
||||
|
@ -157,6 +155,14 @@ export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
|||
<Icon name="editor-link" />
|
||||
</Control>
|
||||
</div>
|
||||
<Show when={showLinkInput()}>
|
||||
<InsertLinkForm
|
||||
editor={instance}
|
||||
onClose={() => {
|
||||
setShowLinkInput(false)
|
||||
recoverSelection()
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -164,7 +170,7 @@ export const MicroEditor = (props: MicroEditorProps): JSX.Element => {
|
|||
)}
|
||||
</Show>
|
||||
|
||||
<div id="micro-editor" ref={setEditorElement} style={styles.minimal} />
|
||||
<div id="micro-editor" ref={setEditorElement} style={styles.minimal} onFocusOut={storeSelection} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -2,13 +2,10 @@ import type { Editor } from '@tiptap/core'
|
|||
import CharacterCount from '@tiptap/extension-character-count'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
import clsx from 'clsx'
|
||||
import { type JSX, Show, createEffect, createSignal, onCleanup } from 'solid-js'
|
||||
import { type JSX, Show, createEffect, createSignal, on, onCleanup } from 'solid-js'
|
||||
import {
|
||||
createEditorTransaction,
|
||||
createTiptapEditor,
|
||||
useEditorHTML,
|
||||
useEditorIsEmpty,
|
||||
useEditorIsFocused
|
||||
} from 'solid-tiptap'
|
||||
import { Toolbar } from 'terracotta'
|
||||
import { Icon } from '~/components/_shared/Icon/Icon'
|
||||
|
@ -63,7 +60,6 @@ export default function MiniEditor(props: MiniEditorProps): JSX.Element {
|
|||
const [editorElement, setEditorElement] = createSignal<HTMLDivElement>()
|
||||
const [counter, setCounter] = createSignal(0)
|
||||
const [showLinkInput, setShowLinkInput] = createSignal(false)
|
||||
const [showSimpleMenu, setShowSimpleMenu] = createSignal(false)
|
||||
const { t } = useLocalize()
|
||||
const { showModal } = useUI()
|
||||
|
||||
|
@ -82,12 +78,9 @@ export default function MiniEditor(props: MiniEditorProps): JSX.Element {
|
|||
content: props.content || ''
|
||||
}))
|
||||
|
||||
const isEmpty = useEditorIsEmpty(editor)
|
||||
const isFocused = useEditorIsFocused(editor)
|
||||
const isTextSelection = createEditorTransaction(editor, (instance) => !instance?.state.selection.empty)
|
||||
const html = useEditorHTML(editor)
|
||||
|
||||
createEffect(() => setShowSimpleMenu(isTextSelection()))
|
||||
createEffect(on(html, (c?: string) => c && props.onChange?.(c)))
|
||||
createEffect(on(showLinkInput, (x?: boolean) => x && editor()?.chain().focus().run()))
|
||||
|
||||
createEffect(() => {
|
||||
const textLength = editor()?.getText().length || 0
|
||||
|
@ -112,13 +105,12 @@ export default function MiniEditor(props: MiniEditorProps): JSX.Element {
|
|||
})
|
||||
return (
|
||||
<div
|
||||
class={clsx(styles.SimplifiedEditor, styles.bordered, {
|
||||
[styles.isFocused]: isEmpty() || isFocused()
|
||||
})}
|
||||
class={clsx(styles.SimplifiedEditor, styles.bordered, styles.isFocused)}
|
||||
>
|
||||
<div>
|
||||
<Show when={showSimpleMenu() || showLinkInput()}>
|
||||
<Toolbar style={{ 'background-color': 'white' }} ref={setToolbarElement} horizontal>
|
||||
<div id="mini-editor" ref={setEditorElement} />
|
||||
|
||||
<Toolbar style={{ 'background-color': 'white', display: 'inline-flex' }} ref={setToolbarElement} horizontal>
|
||||
<Show when={editor()} keyed>
|
||||
{(instance) => (
|
||||
<div class={styles.controls}>
|
||||
|
@ -174,15 +166,13 @@ export default function MiniEditor(props: MiniEditorProps): JSX.Element {
|
|||
)}
|
||||
</Show>
|
||||
</Toolbar>
|
||||
</Show>
|
||||
|
||||
<div id="mini-editor" ref={setEditorElement} />
|
||||
|
||||
<Show when={counter() > 0}>
|
||||
<small class={styles.limit}>
|
||||
{counter()} / {props.limit || '∞'}
|
||||
</small>
|
||||
</Show>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user