From 16ac563eba5b4d1562df8fcbd34331990b296c99 Mon Sep 17 00:00:00 2001 From: Anna No Date: Thu, 12 Oct 2023 17:43:57 +0700 Subject: [PATCH] UBERF-3997: Fix Tab navigation in text editors (#3832) * fix tab focus switch for styled text editor Signed-off-by: Anna No * fix tab focus switch for styled text editor Signed-off-by: Anna No * fix tab focus switch for styled text editor Signed-off-by: Anna No --------- Signed-off-by: Anna No --- .../src/components/StyledTextBox.svelte | 41 +++++++++------- .../src/components/StyledTextEditor.svelte | 8 ---- .../src/components/TextEditor.svelte | 6 +-- .../src/components/extension/focus.ts | 47 +++++++++++++++++++ 4 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 packages/text-editor/src/components/extension/focus.ts diff --git a/packages/text-editor/src/components/StyledTextBox.svelte b/packages/text-editor/src/components/StyledTextBox.svelte index b256412050..48968b0665 100644 --- a/packages/text-editor/src/components/StyledTextBox.svelte +++ b/packages/text-editor/src/components/StyledTextBox.svelte @@ -22,6 +22,7 @@ import { completionConfig } from './extensions' import { EmojiExtension } from './extension/emoji' + import { FocusExtension } from './extension/focus' import { ImageRef, FileAttachFunction } from './imageExt' import { Node as ProseMirrorNode } from '@tiptap/pm/model' @@ -70,6 +71,8 @@ mode = Mode.View } + let canBlur = true + let focused = false let rawValue: string let oldContent = '' let modified: boolean = false @@ -103,7 +106,6 @@ textEditor.setContent(data) } const dispatch = createEventDispatcher() - let focused = false export function isFocused (): boolean { return focused @@ -129,7 +131,7 @@ isFocus: () => focused, canBlur: () => { if (focused) { - return !textEditor.catHandleTab() + return canBlur } return true } @@ -140,6 +142,20 @@ } } + const handleFocus = (value: boolean) => { + focused = value + if (focused) { + updateFocus() + dispatch('focus') + } else { + dispatch('blur', rawValue) + if (alwaysEdit) { + dispatch('value', rawValue) + content = rawValue + } + } + } + const attachments = new Map() /** @@ -169,10 +185,14 @@ } }) - const extensions: AnyExtension[] = [imagePlugin] + const extensions: AnyExtension[] = [] if (enableBackReferences) { - extensions.unshift(completionPlugin) + extensions.push(completionPlugin) } + extensions.push( + imagePlugin, + FocusExtension.configure({ onCanBlur: (value: boolean) => (canBlur = value), onFocus: handleFocus }) + ) if (enableEmojiReplace) { extensions.push(EmojiExtension.configure()) } @@ -217,19 +237,6 @@ bind:content={rawValue} bind:this={textEditor} on:attach - on:focus={() => { - focused = true - updateFocus() - dispatch('focus') - }} - on:blur={() => { - focused = false - dispatch('blur', rawValue) - if (alwaysEdit) { - dispatch('value', rawValue) - content = rawValue - } - }} on:value={(evt) => { rawValue = evt.detail if (alwaysEdit) { diff --git a/packages/text-editor/src/components/StyledTextEditor.svelte b/packages/text-editor/src/components/StyledTextEditor.svelte index 17ee28ba72..de0b5ca84d 100644 --- a/packages/text-editor/src/components/StyledTextEditor.svelte +++ b/packages/text-editor/src/components/StyledTextEditor.svelte @@ -85,14 +85,6 @@ export function insertText (text: string): void { textEditor.insertText(text) } - export function catHandleTab (): boolean { - return ( - textEditor.checkIsActive('bulletList') || - textEditor.checkIsActive('orderedList') || - textEditor.checkIsActive('code') || - textEditor.checkIsActive('codeBlock') - ) - } $: varsStyle = maxHeight === 'card' diff --git a/packages/text-editor/src/components/TextEditor.svelte b/packages/text-editor/src/components/TextEditor.svelte index c512a8baf9..005a81ada9 100644 --- a/packages/text-editor/src/components/TextEditor.svelte +++ b/packages/text-editor/src/components/TextEditor.svelte @@ -165,13 +165,13 @@ // force re-render so `editor.isActive` works as expected editor = editor }, - onBlur: ({ event }) => { + onBlur: () => { focused = false - dispatch('blur', event) + dispatch('blur') }, onFocus: () => { focused = true - dispatch('focus', editor.getHTML()) + dispatch('focus') }, onUpdate: () => { content = editor.getHTML() diff --git a/packages/text-editor/src/components/extension/focus.ts b/packages/text-editor/src/components/extension/focus.ts new file mode 100644 index 0000000000..c8ce46e83f --- /dev/null +++ b/packages/text-editor/src/components/extension/focus.ts @@ -0,0 +1,47 @@ +import { Editor, Extension } from '@tiptap/core' + +const canBlur = (editor: Editor, options: FocusOptions): boolean => { + return ( + options.canBlur?.(editor) ?? + (!editor.isActive('bulletList') && + !editor.isActive('orderedList') && + !editor.isActive('code') && + !editor.isActive('codeBlock')) + ) +} + +export interface FocusOptions { + canBlur?: (editor: Editor) => boolean + onCanBlur?: (canBlur: boolean) => void + onFocus?: (focused: boolean) => void +} + +export interface FocusStorage { + canBlur: boolean +} + +export const FocusExtension = Extension.create({ + addStorage () { + return { canBlur: true } + }, + onCreate () { + this.options.onFocus?.(this.editor.isFocused) + + this.storage.canBlur = canBlur(this.editor, this.options) + this.options.onCanBlur?.(this.storage.canBlur) + }, + onBlur () { + this.options.onFocus?.(false) + }, + onFocus () { + this.options.onFocus?.(true) + }, + onSelectionUpdate () { + const canBlurNow = canBlur(this.editor, this.options) + + if (this.storage.canBlur !== canBlurNow) { + this.storage.canBlur = canBlurNow + this.options.onCanBlur?.(this.storage.canBlur) + } + } +})