Skip to content

Commit

Permalink
Merge branch 'develop' into ordered-list-type
Browse files Browse the repository at this point in the history
  • Loading branch information
bastianjoel authored Jul 15, 2024
2 parents 307dab6 + ff04353 commit fc602cc
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 97 deletions.
51 changes: 16 additions & 35 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions packages/core/src/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,6 @@ export class Editor extends EventEmitter<EditorEvents> {
const state = this.state.apply(transaction)
const selectionHasChanged = !this.state.selection.eq(state.selection)

this.emit('beforeTransaction', {
editor: this,
transaction,
nextState: state,
})
this.view.updateState(state)
this.emit('transaction', {
editor: this,
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export interface EditorEvents {
}
update: { editor: Editor; transaction: Transaction }
selectionUpdate: { editor: Editor; transaction: Transaction }
beforeTransaction: { editor: Editor; transaction: Transaction, nextState: EditorState }
transaction: { editor: Editor; transaction: Transaction }
focus: { editor: Editor; event: FocusEvent; transaction: Transaction }
blur: { editor: Editor; event: FocusEvent; transaction: Transaction }
Expand Down
12 changes: 7 additions & 5 deletions packages/vue-3/src/Editor.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Editor as CoreEditor, EditorOptions } from '@tiptap/core'
import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state'
import {
AppContext,
ComponentInternalInstance,
ComponentPublicInstance,
customRef,
markRaw,
reactive,
Ref,
} from 'vue'

import { VueRenderer } from './VueRenderer.js'

function useDebouncedRef<T>(value: T) {
return customRef<T>((track, trigger) => {
return {
Expand Down Expand Up @@ -40,18 +42,18 @@ export class Editor extends CoreEditor {

private reactiveExtensionStorage: Ref<Record<string, any>>

public contentComponent: ContentComponent | null = null
public vueRenderers = reactive<Map<string, VueRenderer>>(new Map())

public appContext: AppContext | null = null
public contentComponent: ContentComponent | null = null

constructor(options: Partial<EditorOptions> = {}) {
super(options)

this.reactiveState = useDebouncedRef(this.view.state)
this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage)

this.on('beforeTransaction', ({ nextState }) => {
this.reactiveState.value = nextState
this.on('transaction', () => {
this.reactiveState.value = this.view.state
this.reactiveExtensionStorage.value = this.extensionStorage
})

Expand Down
38 changes: 26 additions & 12 deletions packages/vue-3/src/EditorContent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
DefineComponent,
defineComponent,
getCurrentInstance,
h,
Expand All @@ -7,6 +8,7 @@ import {
PropType,
Ref,
ref,
Teleport,
unref,
watchEffect,
} from 'vue'
Expand Down Expand Up @@ -43,17 +45,6 @@ export const EditorContent = defineComponent({
// @ts-ignore
editor.contentComponent = instance.ctx._

if (instance) {
editor.appContext = {
...instance.appContext,
provides: {
// @ts-ignore
...instance.provides,
...instance.appContext.provides,
},
}
}

editor.setOptions({
element,
})
Expand All @@ -78,7 +69,6 @@ export const EditorContent = defineComponent({
}

editor.contentComponent = null
editor.appContext = null

if (!editor.options.element.firstChild) {
return
Expand All @@ -97,11 +87,35 @@ export const EditorContent = defineComponent({
},

render() {
const vueRenderers: any[] = []

if (this.editor) {
this.editor.vueRenderers.forEach(vueRenderer => {
const node = h(
Teleport,
{
to: vueRenderer.teleportElement,
key: vueRenderer.id,
},
h(
vueRenderer.component as DefineComponent,
{
ref: vueRenderer.id,
...vueRenderer.props,
},
),
)

vueRenderers.push(node)
})
}

return h(
'div',
{
ref: (el: any) => { this.rootEl = el },
},
...vueRenderers,
)
},
})
10 changes: 3 additions & 7 deletions packages/vue-3/src/VueNodeViewRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
}

get dom() {
if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) {
if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) {
throw Error('Please use the NodeViewWrapper component for your node view.')
}

Expand Down Expand Up @@ -183,18 +183,14 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
this.renderer.updateProps({
selected: true,
})
if (this.renderer.element) {
this.renderer.element.classList.add('ProseMirror-selectednode')
}
this.renderer.element.classList.add('ProseMirror-selectednode')
}

deselectNode() {
this.renderer.updateProps({
selected: false,
})
if (this.renderer.element) {
this.renderer.element.classList.remove('ProseMirror-selectednode')
}
this.renderer.element.classList.remove('ProseMirror-selectednode')
}

getDecorationClasses() {
Expand Down
49 changes: 17 additions & 32 deletions packages/vue-3/src/VueRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Editor } from '@tiptap/core'
import {
Component, DefineComponent, h, markRaw, reactive, render,
} from 'vue'
import { Component, markRaw, reactive } from 'vue'

import { Editor as ExtendedEditor } from './Editor.js'

Expand All @@ -10,68 +8,55 @@ export interface VueRendererOptions {
props?: Record<string, any>,
}

type ExtendedVNode = ReturnType<typeof h> | null

interface RenderedComponent {
vNode: ExtendedVNode
destroy: () => void
el: Element | null
}

/**
* This class is used to render Vue components inside the editor.
*/
export class VueRenderer {
id: string

renderedComponent!: RenderedComponent

editor: ExtendedEditor

component: Component

el: Element | null
teleportElement: Element

element: Element

props: Record<string, any>

constructor(component: Component, { props = {}, editor }: VueRendererOptions) {
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
this.editor = editor as ExtendedEditor
this.component = markRaw(component)
this.el = document.createElement('div')
this.teleportElement = document.createElement('div')
this.element = this.teleportElement
this.props = reactive(props)
this.renderedComponent = this.renderComponent()
}

get element(): Element | null {
return this.renderedComponent.el
}
this.editor.vueRenderers.set(this.id, this)

renderComponent() {
let vNode: ExtendedVNode = h(this.component as DefineComponent, this.props)
if (this.editor.contentComponent) {
this.editor.contentComponent.update()

if (typeof document !== 'undefined' && this.el) { render(vNode, this.el) }
if (this.teleportElement.children.length !== 1) {
throw Error('VueRenderer doesn’t support multiple child elements.')
}

const destroy = () => {
if (this.el) { render(null, this.el) }
this.el = null
vNode = null
this.element = this.teleportElement.firstElementChild as Element
}
}

return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }
get ref(): any {
return this.editor.contentComponent?.refs[this.id]
}

updateProps(props: Record<string, any> = {}): void {

Object
.entries(props)
.forEach(([key, value]) => {
this.props[key] = value
})
this.renderComponent()
}

destroy(): void {
this.renderedComponent.destroy()
this.editor.vueRenderers.delete(this.id)
}
}

0 comments on commit fc602cc

Please sign in to comment.