Skip to content

Commit

Permalink
QMS: Update inline comments extensions (#3814)
Browse files Browse the repository at this point in the history
* update documents inline comments extensions

Signed-off-by: Anna No <anna.no@xored.com>

* update qms documents inline comments

Signed-off-by: Anna No <anna.no@xored.com>

* qms: update document inline comments extensions

Signed-off-by: Anna No <anna.no@xored.com>

* qms: move highlight to prose mirror decorations

Signed-off-by: Anna No <anna.no@xored.com>

* fix formatting issues

Signed-off-by: Anna No <anna.no@xored.com>

* fix formatting issues

Signed-off-by: Anna No <anna.no@xored.com>

* fix formatting issues

Signed-off-by: Anna No <anna.no@xored.com>

* fix formatting issues

Signed-off-by: Anna No <anna.no@xored.com>

---------

Signed-off-by: Anna No <anna.no@xored.com>
  • Loading branch information
annano authored Oct 9, 2023
1 parent 8805a58 commit 4e08b75
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 133 deletions.
51 changes: 26 additions & 25 deletions packages/text-editor/src/components/CollaboratorEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import { calculateDecorations } from './diff/decorations'
import { defaultEditorAttributes } from './editor/editorProps'
import { completionConfig, defaultExtensions } from './extensions'
import { InlineStyleToolbar } from './extension/inlineStyleToolbar'
import { InlineStyleToolbarExtension } from './extension/inlineStyleToolbar'
import { NodeUuidExtension } from './extension/nodeUuid'
import StyleButton from './StyleButton.svelte'
import TextEditorStyleToolbar from './TextEditorStyleToolbar.svelte'
Expand All @@ -47,7 +47,6 @@
export let token: string
export let collaboratorURL: string
export let isFormatting = true
export let buttonSize: IconSize = 'small'
export let focusable: boolean = false
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
Expand Down Expand Up @@ -90,7 +89,6 @@
let editor: Editor
let inlineToolbar: HTMLElement
let showInlineToolbar = false
let placeHolderStr: string = ''
Expand Down Expand Up @@ -136,7 +134,6 @@
}
const [$start, $end] = [doc.resolve(range.from), doc.resolve(range.to)]
editor.view.dispatch(tr.setSelection(new TextSelection($start, $end)))
needFocus = true
})
Expand All @@ -146,6 +143,22 @@
provider.copyContent(documentId, snapshotId)
}
export function unregisterPlugin (nameOrPluginKey: string | PluginKey) {
if (!editor) {
return
}
editor.unregisterPlugin(nameOrPluginKey)
}
export function registerPlugin (plugin: Plugin) {
if (!editor) {
return
}
editor.registerPlugin(plugin)
}
let needFocus = false
let focused = false
Expand Down Expand Up @@ -201,6 +214,7 @@
})
$: updateEditor(editor, field, comparedVersion)
$: if (editor) dispatch('editor', editor)
onMount(() => {
ph.then(() => {
Expand All @@ -211,10 +225,10 @@
extensions: [
...defaultExtensions,
Placeholder.configure({ placeholder: placeHolderStr }),
InlineStyleToolbar.configure({
InlineStyleToolbarExtension.configure({
element: inlineToolbar,
getEditorElement: () => element,
isShown: () => !readonly && showInlineToolbar
isSupported: () => !readonly,
isSelectionOnly: () => false
}),
Collaboration.configure({
document: ydoc,
Expand Down Expand Up @@ -247,22 +261,14 @@
onFocus: () => {
focused = true
},
onUpdate: ({ editor, transaction }) => {
showInlineToolbar = false
onUpdate: ({ transaction }) => {
// ignore non-document changes
if (!transaction.docChanged) return
// TODO this is heavy and should be replaced with more lightweight event
dispatch('content', editor.getHTML())
// ignore non-local changes
if (isChangeOrigin(transaction)) return
dispatch('update')
},
onSelectionUpdate: () => {
showInlineToolbar = false
}
})
Expand All @@ -283,16 +289,11 @@
}
})
function onEditorClick () {
if (!editor.isEmpty) {
showInlineToolbar = true
}
}
let showDiff = true
</script>

<slot />
<slot {editor} />

{#if visible}
{#if comparedVersion !== undefined || $$slots.tools}
<div class="ref-container" class:autoOverflow>
Expand Down Expand Up @@ -336,15 +337,15 @@
needFocus = true
}}
on:action={(event) => {
dispatch('action', { action: event.detail, editor })
dispatch('action', event.detail)
needFocus = true
}}
/>
</div>

<div class="ref-container" class:autoOverflow>
<div class="textInput" class:focusable>
<div class="select-text" style="width: 100%;" on:mousedown={onEditorClick} bind:this={element} />
<div class="select-text" style="width: 100%;" bind:this={element} />
</div>
</div>
{/if}
Expand Down
21 changes: 5 additions & 16 deletions packages/text-editor/src/components/TextEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import { themeStore } from '@hcengineering/ui'
import TextEditorStyleToolbar from './TextEditorStyleToolbar.svelte'
import { TextFormatCategory } from '../types'
import { InlineStyleToolbar } from './extension/inlineStyleToolbar'
import { InlineStyleToolbarExtension } from './extension/inlineStyleToolbar'
import { defaultEditorAttributes } from './editor/editorProps'
export let content: string = ''
Expand Down Expand Up @@ -77,7 +77,6 @@
let needFocus = false
let focused = false
let posFocus: FocusPosition | undefined = undefined
let showContextMenu = false
let textEditorToolbar: HTMLElement
export function focus (position?: FocusPosition): void {
Expand Down Expand Up @@ -137,10 +136,10 @@
...(supportSubmit ? [Handle] : []), // order important
Placeholder.configure({ placeholder: placeHolderStr }),
...extensions,
InlineStyleToolbar.configure({
InlineStyleToolbarExtension.configure({
element: textEditorToolbar,
getEditorElement: () => element,
isShown: () => showContextMenu
isSupported: () => true,
isSelectionOnly: () => false
})
],
parseOptions: {
Expand All @@ -160,12 +159,8 @@
},
onUpdate: () => {
content = editor.getHTML()
showContextMenu = false
dispatch('value', content)
dispatch('update', content)
},
onSelectionUpdate: () => {
showContextMenu = false
}
})
})
Expand All @@ -177,12 +172,6 @@
}
})
function onEditorClick () {
if (!editor.isEmpty) {
showContextMenu = true
}
}
/**
* @public
*/
Expand All @@ -209,7 +198,7 @@
}}
/>
</div>
<div class="select-text" style="width: 100%;" on:mousedown={onEditorClick} bind:this={element} />
<div class="select-text" style="width: 100%;" bind:this={element} />

<style lang="scss">
.formatPanel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@
disabled={textEditor.view.state.selection.empty}
showTooltip={{ label: action.label }}
on:click={() => {
dispatch('action', action.id)
dispatch('action', { action: action.id, editor: textEditor })
}}
/>
{/each}
Expand Down
16 changes: 16 additions & 0 deletions packages/text-editor/src/components/extension/inlinePopup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Extension } from '@tiptap/core'
import BubbleMenu, { BubbleMenuOptions } from '@tiptap/extension-bubble-menu'

export const InlinePopupExtension: Extension<BubbleMenuOptions> = BubbleMenu.extend({
addOptions () {
return {
...this.parent?.(),
pluginKey: 'inline-popup',
element: null,
tippyOptions: {
maxWidth: '38rem',
appendTo: () => document.body
}
}
}
})
99 changes: 73 additions & 26 deletions packages/text-editor/src/components/extension/inlineStyleToolbar.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,86 @@
import { Extension, isTextSelection } from '@tiptap/core'
import BubbleMenu, { BubbleMenuOptions } from '@tiptap/extension-bubble-menu'
import { Editor, Extension, isTextSelection } from '@tiptap/core'
import { BubbleMenuOptions } from '@tiptap/extension-bubble-menu'
import { Plugin, PluginKey } from 'prosemirror-state'
import { InlinePopupExtension } from './inlinePopup'

type InlineStyleToolbarOptions = BubbleMenuOptions & {
getEditorElement: () => HTMLElement | null | undefined
isShown?: () => boolean
export type InlineStyleToolbarOptions = BubbleMenuOptions & {
isSupported: () => boolean
isSelectionOnly?: () => boolean
}

export const InlineStyleToolbar = Extension.create<InlineStyleToolbarOptions>({
defaultOptions: {
pluginKey: 'inline-style-toolbar',
element: null,
tippyOptions: {
maxWidth: '38rem',
appendTo: () => document.body
},
getEditorElement: () => null
export interface InlineStyleToolbarStorage {
isShown: boolean
}

const handleFocus = (editor: Editor, options: InlineStyleToolbarOptions, storage: InlineStyleToolbarStorage): void => {
if (!options.isSupported()) {
return
}

if (editor.isEmpty) {
return
}

if (options.isSelectionOnly?.() === true && editor.view.state.selection.empty) {
return
}

storage.isShown = true
}

export const InlineStyleToolbarExtension = Extension.create<InlineStyleToolbarOptions, InlineStyleToolbarStorage>({
pluginKey: new PluginKey('inline-style-toolbar'),
addProseMirrorPlugins () {
const options = this.options
const storage = this.storage
const editor = this.editor

const plugins = [
...(this.parent?.() ?? []),
new Plugin({
key: new PluginKey('inline-style-toolbar-click-plugin'),
props: {
handleClick () {
handleFocus(editor, options, storage)
}
}
})
]

return plugins
},
addStorage () {
return {
isShown: false
}
},
addExtensions () {
const options: InlineStyleToolbarOptions = this.options

return [
BubbleMenu.configure({
InlinePopupExtension.configure({
...options,
// to override shouldShow behaviour a little
// I need to copypaste original function and make a little change
// with showContextMenu falg
shouldShow: ({ editor, view, state, oldState, from, to }) => {
const editorElement = options.getEditorElement()
// For some reason shouldShow might be called after dismount and
// after destroing the editor. We should handle this just no to have
// any errors in runtime
if (editorElement === null || editorElement === undefined) {
if (!this.options.isSupported()) {
return false
}

if (!editor.isEditable) {
if (editor.isDestroyed || !editor.isEditable) {
return false
}

const isShown = options.isShown?.() ?? false
if (isShown) {
if (this.storage.isShown) {
return true
}

// For some reason shouldShow might be called after dismount and
// after destroing the editor. We should handle this just no to have
// any errors in runtime
const editorElement = editor.view.dom
if (editorElement === null || editorElement === undefined) {
return false
}

// When clicking on a element inside the bubble menu the editor "blur" event
// is called and the bubble menu item is focussed. In this case we should
// consider the menu as part of the editor and keep showing the menu
Expand All @@ -67,5 +105,14 @@ export const InlineStyleToolbar = Extension.create<InlineStyleToolbarOptions>({
}
})
]
},
onFocus () {
handleFocus(this.editor, this.options, this.storage)
},
onSelectionUpdate () {
this.storage.isShown = false
},
onUpdate () {
this.storage.isShown = false
}
})
Loading

0 comments on commit 4e08b75

Please sign in to comment.