mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-12 20:57:45 +02:00
UBERF-3997: Fix Tab navigation in text editors (#3832)
* fix tab focus switch for styled text editor Signed-off-by: Anna No <anna.no@xored.com> * fix tab focus switch for styled text editor Signed-off-by: Anna No <anna.no@xored.com> * fix tab focus switch for styled text editor Signed-off-by: Anna No <anna.no@xored.com> --------- Signed-off-by: Anna No <anna.no@xored.com>
This commit is contained in:
@@ -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<string, ProseMirrorNode>()
|
||||
|
||||
/**
|
||||
@@ -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) {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<FocusOptions, FocusStorage>({
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user