@tiptap/vue-3
Advanced tools
Comparing version 3.0.0-next.0 to 3.0.0-next.1
1008
dist/index.js
@@ -1,504 +0,582 @@ | ||
import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'; | ||
import { defineComponent, ref, onMounted, onBeforeUnmount, h, Teleport, markRaw, customRef, getCurrentInstance, watchEffect, nextTick, unref, shallowRef, reactive, render, provide } from 'vue'; | ||
import { Editor as Editor$1, NodeView } from '@tiptap/core'; | ||
export * from '@tiptap/core'; | ||
import { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'; | ||
const BubbleMenu = defineComponent({ | ||
name: 'BubbleMenu', | ||
props: { | ||
pluginKey: { | ||
type: [String, Object], | ||
default: 'bubbleMenu', | ||
}, | ||
editor: { | ||
type: Object, | ||
required: true, | ||
}, | ||
updateDelay: { | ||
type: Number, | ||
default: undefined, | ||
}, | ||
resizeDelay: { | ||
type: Number, | ||
default: undefined, | ||
}, | ||
options: { | ||
type: Object, | ||
default: () => ({}), | ||
}, | ||
shouldShow: { | ||
type: Function, | ||
default: null, | ||
}, | ||
// src/BubbleMenu.ts | ||
import { BubbleMenuPlugin } from "@tiptap/extension-bubble-menu"; | ||
import { | ||
defineComponent, | ||
h, | ||
onBeforeUnmount, | ||
onMounted, | ||
ref, | ||
Teleport | ||
} from "vue"; | ||
var BubbleMenu = defineComponent({ | ||
name: "BubbleMenu", | ||
props: { | ||
pluginKey: { | ||
type: [String, Object], | ||
default: "bubbleMenu" | ||
}, | ||
setup(props, { slots }) { | ||
const root = ref(null); | ||
onMounted(() => { | ||
const { editor, options, pluginKey, resizeDelay, shouldShow, updateDelay, } = props; | ||
if (!root.value) { | ||
return; | ||
} | ||
root.value.style.visibility = 'hidden'; | ||
root.value.style.position = 'absolute'; | ||
// remove the element from the DOM | ||
root.value.remove(); | ||
editor.registerPlugin(BubbleMenuPlugin({ | ||
editor, | ||
element: root.value, | ||
options, | ||
pluginKey, | ||
resizeDelay, | ||
shouldShow, | ||
updateDelay, | ||
})); | ||
}); | ||
onBeforeUnmount(() => { | ||
const { pluginKey, editor } = props; | ||
editor.unregisterPlugin(pluginKey); | ||
}); | ||
return () => { var _a; return h(Teleport, { to: 'body' }, h('div', { ref: root }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots))); }; | ||
editor: { | ||
type: Object, | ||
required: true | ||
}, | ||
updateDelay: { | ||
type: Number, | ||
default: void 0 | ||
}, | ||
resizeDelay: { | ||
type: Number, | ||
default: void 0 | ||
}, | ||
options: { | ||
type: Object, | ||
default: () => ({}) | ||
}, | ||
shouldShow: { | ||
type: Function, | ||
default: null | ||
} | ||
}, | ||
setup(props, { slots }) { | ||
const root = ref(null); | ||
onMounted(() => { | ||
const { | ||
editor, | ||
options, | ||
pluginKey, | ||
resizeDelay, | ||
shouldShow, | ||
updateDelay | ||
} = props; | ||
if (!root.value) { | ||
return; | ||
} | ||
root.value.style.visibility = "hidden"; | ||
root.value.style.position = "absolute"; | ||
root.value.remove(); | ||
editor.registerPlugin(BubbleMenuPlugin({ | ||
editor, | ||
element: root.value, | ||
options, | ||
pluginKey, | ||
resizeDelay, | ||
shouldShow, | ||
updateDelay | ||
})); | ||
}); | ||
onBeforeUnmount(() => { | ||
const { pluginKey, editor } = props; | ||
editor.unregisterPlugin(pluginKey); | ||
}); | ||
return () => { | ||
var _a; | ||
return h(Teleport, { to: "body" }, h("div", { ref: root }, (_a = slots.default) == null ? void 0 : _a.call(slots))); | ||
}; | ||
} | ||
}); | ||
// src/Editor.ts | ||
import { Editor as CoreEditor } from "@tiptap/core"; | ||
import { | ||
customRef, | ||
markRaw | ||
} from "vue"; | ||
function useDebouncedRef(value) { | ||
return customRef((track, trigger) => { | ||
return { | ||
get() { | ||
track(); | ||
return value; | ||
}, | ||
set(newValue) { | ||
// update state | ||
value = newValue; | ||
// update view as soon as possible | ||
requestAnimationFrame(() => { | ||
requestAnimationFrame(() => { | ||
trigger(); | ||
}); | ||
}); | ||
}, | ||
}; | ||
}); | ||
} | ||
class Editor extends Editor$1 { | ||
constructor(options = {}) { | ||
super(options); | ||
this.contentComponent = null; | ||
this.appContext = null; | ||
this.reactiveState = useDebouncedRef(this.view.state); | ||
this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage); | ||
this.on('beforeTransaction', ({ nextState }) => { | ||
this.reactiveState.value = nextState; | ||
this.reactiveExtensionStorage.value = this.extensionStorage; | ||
return customRef((track, trigger) => { | ||
return { | ||
get() { | ||
track(); | ||
return value; | ||
}, | ||
set(newValue) { | ||
value = newValue; | ||
requestAnimationFrame(() => { | ||
requestAnimationFrame(() => { | ||
trigger(); | ||
}); | ||
}); | ||
return markRaw(this); // eslint-disable-line | ||
} | ||
get state() { | ||
return this.reactiveState ? this.reactiveState.value : this.view.state; | ||
} | ||
get storage() { | ||
return this.reactiveExtensionStorage ? this.reactiveExtensionStorage.value : super.storage; | ||
} | ||
/** | ||
* Register a ProseMirror plugin. | ||
*/ | ||
registerPlugin(plugin, handlePlugins) { | ||
super.registerPlugin(plugin, handlePlugins); | ||
this.reactiveState.value = this.view.state; | ||
} | ||
/** | ||
* Unregister a ProseMirror plugin. | ||
*/ | ||
unregisterPlugin(nameOrPluginKey) { | ||
super.unregisterPlugin(nameOrPluginKey); | ||
this.reactiveState.value = this.view.state; | ||
} | ||
} | ||
}; | ||
}); | ||
} | ||
var Editor = class extends CoreEditor { | ||
constructor(options = {}) { | ||
super(options); | ||
this.contentComponent = null; | ||
this.appContext = null; | ||
this.reactiveState = useDebouncedRef(this.view.state); | ||
this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage); | ||
this.on("beforeTransaction", ({ nextState }) => { | ||
this.reactiveState.value = nextState; | ||
this.reactiveExtensionStorage.value = this.extensionStorage; | ||
}); | ||
return markRaw(this); | ||
} | ||
get state() { | ||
return this.reactiveState ? this.reactiveState.value : this.view.state; | ||
} | ||
get storage() { | ||
return this.reactiveExtensionStorage ? this.reactiveExtensionStorage.value : super.storage; | ||
} | ||
/** | ||
* Register a ProseMirror plugin. | ||
*/ | ||
registerPlugin(plugin, handlePlugins) { | ||
super.registerPlugin(plugin, handlePlugins); | ||
this.reactiveState.value = this.view.state; | ||
} | ||
/** | ||
* Unregister a ProseMirror plugin. | ||
*/ | ||
unregisterPlugin(nameOrPluginKey) { | ||
super.unregisterPlugin(nameOrPluginKey); | ||
this.reactiveState.value = this.view.state; | ||
} | ||
}; | ||
const EditorContent = defineComponent({ | ||
name: 'EditorContent', | ||
props: { | ||
editor: { | ||
default: null, | ||
type: Object, | ||
}, | ||
}, | ||
setup(props) { | ||
const rootEl = ref(); | ||
const instance = getCurrentInstance(); | ||
watchEffect(() => { | ||
const editor = props.editor; | ||
if (editor && editor.options.element && rootEl.value) { | ||
nextTick(() => { | ||
if (!rootEl.value || !editor.options.element.firstChild) { | ||
return; | ||
} | ||
const element = unref(rootEl.value); | ||
rootEl.value.append(...editor.options.element.childNodes); | ||
// @ts-ignore | ||
editor.contentComponent = instance.ctx._; | ||
if (instance) { | ||
editor.appContext = { | ||
...instance.appContext, | ||
// Vue internally uses prototype chain to forward/shadow injects across the entire component chain | ||
// so don't use object spread operator or 'Object.assign' and just set `provides` as is on editor's appContext | ||
// @ts-expect-error forward instance's 'provides' into appContext | ||
provides: instance.provides, | ||
}; | ||
} | ||
editor.setOptions({ | ||
element, | ||
}); | ||
editor.createNodeViews(); | ||
}); | ||
} | ||
// src/EditorContent.ts | ||
import { | ||
defineComponent as defineComponent2, | ||
getCurrentInstance, | ||
h as h2, | ||
nextTick, | ||
onBeforeUnmount as onBeforeUnmount2, | ||
ref as ref2, | ||
unref, | ||
watchEffect | ||
} from "vue"; | ||
var EditorContent = defineComponent2({ | ||
name: "EditorContent", | ||
props: { | ||
editor: { | ||
default: null, | ||
type: Object | ||
} | ||
}, | ||
setup(props) { | ||
const rootEl = ref2(); | ||
const instance = getCurrentInstance(); | ||
watchEffect(() => { | ||
const editor = props.editor; | ||
if (editor && editor.options.element && rootEl.value) { | ||
nextTick(() => { | ||
if (!rootEl.value || !editor.options.element.firstChild) { | ||
return; | ||
} | ||
const element = unref(rootEl.value); | ||
rootEl.value.append(...editor.options.element.childNodes); | ||
editor.contentComponent = instance.ctx._; | ||
if (instance) { | ||
editor.appContext = { | ||
...instance.appContext, | ||
// Vue internally uses prototype chain to forward/shadow injects across the entire component chain | ||
// so don't use object spread operator or 'Object.assign' and just set `provides` as is on editor's appContext | ||
// @ts-expect-error forward instance's 'provides' into appContext | ||
provides: instance.provides | ||
}; | ||
} | ||
editor.setOptions({ | ||
element | ||
}); | ||
editor.createNodeViews(); | ||
}); | ||
onBeforeUnmount(() => { | ||
const editor = props.editor; | ||
if (!editor) { | ||
return; | ||
} | ||
// destroy nodeviews before vue removes dom element | ||
if (!editor.isDestroyed) { | ||
editor.view.setProps({ | ||
nodeViews: {}, | ||
}); | ||
} | ||
editor.contentComponent = null; | ||
editor.appContext = null; | ||
if (!editor.options.element.firstChild) { | ||
return; | ||
} | ||
const newElement = document.createElement('div'); | ||
newElement.append(...editor.options.element.childNodes); | ||
editor.setOptions({ | ||
element: newElement, | ||
}); | ||
} | ||
}); | ||
onBeforeUnmount2(() => { | ||
const editor = props.editor; | ||
if (!editor) { | ||
return; | ||
} | ||
if (!editor.isDestroyed) { | ||
editor.view.setProps({ | ||
nodeViews: {} | ||
}); | ||
return { rootEl }; | ||
}, | ||
render() { | ||
return h('div', { | ||
ref: (el) => { this.rootEl = el; }, | ||
}); | ||
}, | ||
} | ||
editor.contentComponent = null; | ||
editor.appContext = null; | ||
if (!editor.options.element.firstChild) { | ||
return; | ||
} | ||
const newElement = document.createElement("div"); | ||
newElement.append(...editor.options.element.childNodes); | ||
editor.setOptions({ | ||
element: newElement | ||
}); | ||
}); | ||
return { rootEl }; | ||
}, | ||
render() { | ||
return h2( | ||
"div", | ||
{ | ||
ref: (el) => { | ||
this.rootEl = el; | ||
} | ||
} | ||
); | ||
} | ||
}); | ||
const FloatingMenu = defineComponent({ | ||
name: 'FloatingMenu', | ||
props: { | ||
pluginKey: { | ||
// TODO: TypeScript breaks :( | ||
// type: [String, Object as PropType<Exclude<FloatingMenuPluginProps['pluginKey'], string>>], | ||
type: null, | ||
default: 'floatingMenu', | ||
}, | ||
editor: { | ||
type: Object, | ||
required: true, | ||
}, | ||
options: { | ||
type: Object, | ||
default: () => ({}), | ||
}, | ||
shouldShow: { | ||
type: Function, | ||
default: null, | ||
}, | ||
// src/FloatingMenu.ts | ||
import { FloatingMenuPlugin } from "@tiptap/extension-floating-menu"; | ||
import { | ||
defineComponent as defineComponent3, | ||
h as h3, | ||
onBeforeUnmount as onBeforeUnmount3, | ||
onMounted as onMounted2, | ||
ref as ref3, | ||
Teleport as Teleport2 | ||
} from "vue"; | ||
var FloatingMenu = defineComponent3({ | ||
name: "FloatingMenu", | ||
props: { | ||
pluginKey: { | ||
// TODO: TypeScript breaks :( | ||
// type: [String, Object as PropType<Exclude<FloatingMenuPluginProps['pluginKey'], string>>], | ||
type: null, | ||
default: "floatingMenu" | ||
}, | ||
setup(props, { slots }) { | ||
const root = ref(null); | ||
onMounted(() => { | ||
const { pluginKey, editor, options, shouldShow, } = props; | ||
if (!root.value) { | ||
return; | ||
} | ||
root.value.style.visibility = 'hidden'; | ||
root.value.style.position = 'absolute'; | ||
// remove the element from the DOM | ||
root.value.remove(); | ||
editor.registerPlugin(FloatingMenuPlugin({ | ||
pluginKey, | ||
editor, | ||
element: root.value, | ||
options, | ||
shouldShow, | ||
})); | ||
}); | ||
onBeforeUnmount(() => { | ||
const { pluginKey, editor } = props; | ||
editor.unregisterPlugin(pluginKey); | ||
}); | ||
return () => { var _a; return h(Teleport, { to: 'body' }, h('div', { ref: root }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots))); }; | ||
editor: { | ||
type: Object, | ||
required: true | ||
}, | ||
options: { | ||
type: Object, | ||
default: () => ({}) | ||
}, | ||
shouldShow: { | ||
type: Function, | ||
default: null | ||
} | ||
}, | ||
setup(props, { slots }) { | ||
const root = ref3(null); | ||
onMounted2(() => { | ||
const { | ||
pluginKey, | ||
editor, | ||
options, | ||
shouldShow | ||
} = props; | ||
if (!root.value) { | ||
return; | ||
} | ||
root.value.style.visibility = "hidden"; | ||
root.value.style.position = "absolute"; | ||
root.value.remove(); | ||
editor.registerPlugin(FloatingMenuPlugin({ | ||
pluginKey, | ||
editor, | ||
element: root.value, | ||
options, | ||
shouldShow | ||
})); | ||
}); | ||
onBeforeUnmount3(() => { | ||
const { pluginKey, editor } = props; | ||
editor.unregisterPlugin(pluginKey); | ||
}); | ||
return () => { | ||
var _a; | ||
return h3(Teleport2, { to: "body" }, h3("div", { ref: root }, (_a = slots.default) == null ? void 0 : _a.call(slots))); | ||
}; | ||
} | ||
}); | ||
const NodeViewContent = defineComponent({ | ||
name: 'NodeViewContent', | ||
props: { | ||
as: { | ||
type: String, | ||
default: 'div', | ||
}, | ||
}, | ||
render() { | ||
return h(this.as, { | ||
style: { | ||
whiteSpace: 'pre-wrap', | ||
}, | ||
'data-node-view-content': '', | ||
}); | ||
}, | ||
// src/NodeViewContent.ts | ||
import { defineComponent as defineComponent4, h as h4 } from "vue"; | ||
var NodeViewContent = defineComponent4({ | ||
name: "NodeViewContent", | ||
props: { | ||
as: { | ||
type: String, | ||
default: "div" | ||
} | ||
}, | ||
render() { | ||
return h4(this.as, { | ||
style: { | ||
whiteSpace: "pre-wrap" | ||
}, | ||
"data-node-view-content": "" | ||
}); | ||
} | ||
}); | ||
const NodeViewWrapper = defineComponent({ | ||
name: 'NodeViewWrapper', | ||
props: { | ||
as: { | ||
type: String, | ||
default: 'div', | ||
// src/NodeViewWrapper.ts | ||
import { defineComponent as defineComponent5, h as h5 } from "vue"; | ||
var NodeViewWrapper = defineComponent5({ | ||
name: "NodeViewWrapper", | ||
props: { | ||
as: { | ||
type: String, | ||
default: "div" | ||
} | ||
}, | ||
inject: ["onDragStart", "decorationClasses"], | ||
render() { | ||
var _a, _b; | ||
return h5( | ||
this.as, | ||
{ | ||
// @ts-ignore | ||
class: this.decorationClasses, | ||
style: { | ||
whiteSpace: "normal" | ||
}, | ||
}, | ||
inject: ['onDragStart', 'decorationClasses'], | ||
render() { | ||
var _a, _b; | ||
return h(this.as, { | ||
// @ts-ignore | ||
class: this.decorationClasses, | ||
style: { | ||
whiteSpace: 'normal', | ||
}, | ||
'data-node-view-wrapper': '', | ||
// @ts-ignore (https://github.com/vuejs/vue-next/issues/3031) | ||
onDragstart: this.onDragStart, | ||
}, (_b = (_a = this.$slots).default) === null || _b === void 0 ? void 0 : _b.call(_a)); | ||
}, | ||
"data-node-view-wrapper": "", | ||
// @ts-ignore (https://github.com/vuejs/vue-next/issues/3031) | ||
onDragstart: this.onDragStart | ||
}, | ||
(_b = (_a = this.$slots).default) == null ? void 0 : _b.call(_a) | ||
); | ||
} | ||
}); | ||
const useEditor = (options = {}) => { | ||
const editor = shallowRef(); | ||
onMounted(() => { | ||
editor.value = new Editor(options); | ||
}); | ||
onBeforeUnmount(() => { | ||
var _a; | ||
(_a = editor.value) === null || _a === void 0 ? void 0 : _a.destroy(); | ||
}); | ||
return editor; | ||
// src/useEditor.ts | ||
import { onBeforeUnmount as onBeforeUnmount4, onMounted as onMounted3, shallowRef } from "vue"; | ||
var useEditor = (options = {}) => { | ||
const editor = shallowRef(); | ||
onMounted3(() => { | ||
editor.value = new Editor(options); | ||
}); | ||
onBeforeUnmount4(() => { | ||
var _a; | ||
(_a = editor.value) == null ? void 0 : _a.destroy(); | ||
}); | ||
return editor; | ||
}; | ||
/** | ||
* This class is used to render Vue components inside the editor. | ||
*/ | ||
class VueRenderer { | ||
constructor(component, { props = {}, editor }) { | ||
this.editor = editor; | ||
this.component = markRaw(component); | ||
this.el = document.createElement('div'); | ||
this.props = reactive(props); | ||
this.renderedComponent = this.renderComponent(); | ||
// src/VueNodeViewRenderer.ts | ||
import { | ||
NodeView | ||
} from "@tiptap/core"; | ||
import { | ||
defineComponent as defineComponent6, | ||
provide, | ||
ref as ref4 | ||
} from "vue"; | ||
// src/VueRenderer.ts | ||
import { | ||
h as h6, | ||
markRaw as markRaw2, | ||
reactive, | ||
render | ||
} from "vue"; | ||
var VueRenderer = class { | ||
constructor(component, { props = {}, editor }) { | ||
this.editor = editor; | ||
this.component = markRaw2(component); | ||
this.el = document.createElement("div"); | ||
this.props = reactive(props); | ||
this.renderedComponent = this.renderComponent(); | ||
} | ||
get element() { | ||
return this.renderedComponent.el; | ||
} | ||
get ref() { | ||
var _a, _b, _c, _d; | ||
if ((_b = (_a = this.renderedComponent.vNode) == null ? void 0 : _a.component) == null ? void 0 : _b.exposed) { | ||
return this.renderedComponent.vNode.component.exposed; | ||
} | ||
get element() { | ||
return this.renderedComponent.el; | ||
return (_d = (_c = this.renderedComponent.vNode) == null ? void 0 : _c.component) == null ? void 0 : _d.proxy; | ||
} | ||
renderComponent() { | ||
let vNode = h6(this.component, this.props); | ||
if (this.editor.appContext) { | ||
vNode.appContext = this.editor.appContext; | ||
} | ||
get ref() { | ||
var _a, _b, _c, _d; | ||
// Composition API | ||
if ((_b = (_a = this.renderedComponent.vNode) === null || _a === void 0 ? void 0 : _a.component) === null || _b === void 0 ? void 0 : _b.exposed) { | ||
return this.renderedComponent.vNode.component.exposed; | ||
} | ||
// Option API | ||
return (_d = (_c = this.renderedComponent.vNode) === null || _c === void 0 ? void 0 : _c.component) === null || _d === void 0 ? void 0 : _d.proxy; | ||
if (typeof document !== "undefined" && this.el) { | ||
render(vNode, this.el); | ||
} | ||
renderComponent() { | ||
let vNode = h(this.component, this.props); | ||
if (this.editor.appContext) { | ||
vNode.appContext = this.editor.appContext; | ||
} | ||
if (typeof document !== 'undefined' && this.el) { | ||
render(vNode, this.el); | ||
} | ||
const destroy = () => { | ||
if (this.el) { | ||
render(null, this.el); | ||
} | ||
this.el = null; | ||
vNode = null; | ||
}; | ||
return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }; | ||
} | ||
updateProps(props = {}) { | ||
Object.entries(props).forEach(([key, value]) => { | ||
this.props[key] = value; | ||
}); | ||
this.renderComponent(); | ||
} | ||
destroy() { | ||
this.renderedComponent.destroy(); | ||
} | ||
} | ||
const destroy = () => { | ||
if (this.el) { | ||
render(null, this.el); | ||
} | ||
this.el = null; | ||
vNode = null; | ||
}; | ||
return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }; | ||
} | ||
updateProps(props = {}) { | ||
Object.entries(props).forEach(([key, value]) => { | ||
this.props[key] = value; | ||
}); | ||
this.renderComponent(); | ||
} | ||
destroy() { | ||
this.renderedComponent.destroy(); | ||
} | ||
}; | ||
const nodeViewProps = { | ||
editor: { | ||
type: Object, | ||
required: true, | ||
}, | ||
node: { | ||
type: Object, | ||
required: true, | ||
}, | ||
decorations: { | ||
type: Object, | ||
required: true, | ||
}, | ||
selected: { | ||
type: Boolean, | ||
required: true, | ||
}, | ||
extension: { | ||
type: Object, | ||
required: true, | ||
}, | ||
getPos: { | ||
type: Function, | ||
required: true, | ||
}, | ||
updateAttributes: { | ||
type: Function, | ||
required: true, | ||
}, | ||
deleteNode: { | ||
type: Function, | ||
required: true, | ||
}, | ||
// src/VueNodeViewRenderer.ts | ||
var nodeViewProps = { | ||
editor: { | ||
type: Object, | ||
required: true | ||
}, | ||
node: { | ||
type: Object, | ||
required: true | ||
}, | ||
decorations: { | ||
type: Object, | ||
required: true | ||
}, | ||
selected: { | ||
type: Boolean, | ||
required: true | ||
}, | ||
extension: { | ||
type: Object, | ||
required: true | ||
}, | ||
getPos: { | ||
type: Function, | ||
required: true | ||
}, | ||
updateAttributes: { | ||
type: Function, | ||
required: true | ||
}, | ||
deleteNode: { | ||
type: Function, | ||
required: true | ||
} | ||
}; | ||
class VueNodeView extends NodeView { | ||
mount() { | ||
const props = { | ||
editor: this.editor, | ||
node: this.node, | ||
decorations: this.decorations, | ||
selected: false, | ||
extension: this.extension, | ||
getPos: () => this.getPos(), | ||
updateAttributes: (attributes = {}) => this.updateAttributes(attributes), | ||
deleteNode: () => this.deleteNode(), | ||
}; | ||
const onDragStart = this.onDragStart.bind(this); | ||
this.decorationClasses = ref(this.getDecorationClasses()); | ||
const extendedComponent = defineComponent({ | ||
extends: { ...this.component }, | ||
props: Object.keys(props), | ||
template: this.component.template, | ||
setup: reactiveProps => { | ||
var _a, _b; | ||
provide('onDragStart', onDragStart); | ||
provide('decorationClasses', this.decorationClasses); | ||
return (_b = (_a = this.component).setup) === null || _b === void 0 ? void 0 : _b.call(_a, reactiveProps, { | ||
expose: () => undefined, | ||
}); | ||
}, | ||
// add support for scoped styles | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__scopeId: this.component.__scopeId, | ||
// add support for CSS Modules | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__cssModules: this.component.__cssModules, | ||
// add support for vue devtools | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__name: this.component.__name, | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__file: this.component.__file, | ||
var VueNodeView = class extends NodeView { | ||
mount() { | ||
const props = { | ||
editor: this.editor, | ||
node: this.node, | ||
decorations: this.decorations, | ||
selected: false, | ||
extension: this.extension, | ||
getPos: () => this.getPos(), | ||
updateAttributes: (attributes = {}) => this.updateAttributes(attributes), | ||
deleteNode: () => this.deleteNode() | ||
}; | ||
const onDragStart = this.onDragStart.bind(this); | ||
this.decorationClasses = ref4(this.getDecorationClasses()); | ||
const extendedComponent = defineComponent6({ | ||
extends: { ...this.component }, | ||
props: Object.keys(props), | ||
template: this.component.template, | ||
setup: (reactiveProps) => { | ||
var _a, _b; | ||
provide("onDragStart", onDragStart); | ||
provide("decorationClasses", this.decorationClasses); | ||
return (_b = (_a = this.component).setup) == null ? void 0 : _b.call(_a, reactiveProps, { | ||
expose: () => void 0 | ||
}); | ||
this.renderer = new VueRenderer(extendedComponent, { | ||
editor: this.editor, | ||
props, | ||
}); | ||
}, | ||
// add support for scoped styles | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__scopeId: this.component.__scopeId, | ||
// add support for CSS Modules | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__cssModules: this.component.__cssModules, | ||
// add support for vue devtools | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__name: this.component.__name, | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
__file: this.component.__file | ||
}); | ||
this.renderer = new VueRenderer(extendedComponent, { | ||
editor: this.editor, | ||
props | ||
}); | ||
} | ||
get dom() { | ||
if (!this.renderer.element || !this.renderer.element.hasAttribute("data-node-view-wrapper")) { | ||
throw Error("Please use the NodeViewWrapper component for your node view."); | ||
} | ||
get dom() { | ||
if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
throw Error('Please use the NodeViewWrapper component for your node view.'); | ||
} | ||
return this.renderer.element; | ||
return this.renderer.element; | ||
} | ||
get contentDOM() { | ||
if (this.node.isLeaf) { | ||
return null; | ||
} | ||
get contentDOM() { | ||
if (this.node.isLeaf) { | ||
return null; | ||
} | ||
return this.dom.querySelector('[data-node-view-content]'); | ||
return this.dom.querySelector("[data-node-view-content]"); | ||
} | ||
update(node, decorations) { | ||
const updateProps = (props) => { | ||
this.decorationClasses.value = this.getDecorationClasses(); | ||
this.renderer.updateProps(props); | ||
}; | ||
if (typeof this.options.update === "function") { | ||
const oldNode = this.node; | ||
const oldDecorations = this.decorations; | ||
this.node = node; | ||
this.decorations = decorations; | ||
return this.options.update({ | ||
oldNode, | ||
oldDecorations, | ||
newNode: node, | ||
newDecorations: decorations, | ||
updateProps: () => updateProps({ node, decorations }) | ||
}); | ||
} | ||
update(node, decorations) { | ||
const updateProps = (props) => { | ||
this.decorationClasses.value = this.getDecorationClasses(); | ||
this.renderer.updateProps(props); | ||
}; | ||
if (typeof this.options.update === 'function') { | ||
const oldNode = this.node; | ||
const oldDecorations = this.decorations; | ||
this.node = node; | ||
this.decorations = decorations; | ||
return this.options.update({ | ||
oldNode, | ||
oldDecorations, | ||
newNode: node, | ||
newDecorations: decorations, | ||
updateProps: () => updateProps({ node, decorations }), | ||
}); | ||
} | ||
if (node.type !== this.node.type) { | ||
return false; | ||
} | ||
if (node === this.node && this.decorations === decorations) { | ||
return true; | ||
} | ||
this.node = node; | ||
this.decorations = decorations; | ||
updateProps({ node, decorations }); | ||
return true; | ||
if (node.type !== this.node.type) { | ||
return false; | ||
} | ||
selectNode() { | ||
this.renderer.updateProps({ | ||
selected: true, | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add('ProseMirror-selectednode'); | ||
} | ||
if (node === this.node && this.decorations === decorations) { | ||
return true; | ||
} | ||
deselectNode() { | ||
this.renderer.updateProps({ | ||
selected: false, | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove('ProseMirror-selectednode'); | ||
} | ||
this.node = node; | ||
this.decorations = decorations; | ||
updateProps({ node, decorations }); | ||
return true; | ||
} | ||
selectNode() { | ||
this.renderer.updateProps({ | ||
selected: true | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add("ProseMirror-selectednode"); | ||
} | ||
getDecorationClasses() { | ||
return (this.decorations | ||
// @ts-ignore | ||
.map(item => item.type.attrs.class) | ||
.flat() | ||
.join(' ')); | ||
} | ||
deselectNode() { | ||
this.renderer.updateProps({ | ||
selected: false | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove("ProseMirror-selectednode"); | ||
} | ||
destroy() { | ||
this.renderer.destroy(); | ||
} | ||
getDecorationClasses() { | ||
return this.decorations.map((item) => item.type.attrs.class).flat().join(" "); | ||
} | ||
destroy() { | ||
this.renderer.destroy(); | ||
} | ||
}; | ||
function VueNodeViewRenderer(component, options) { | ||
return (props) => { | ||
if (!props.editor.contentComponent) { | ||
return {}; | ||
} | ||
const normalizedComponent = typeof component === "function" && "__vccOpts" in component ? component.__vccOpts : component; | ||
return new VueNodeView(normalizedComponent, props, options); | ||
}; | ||
} | ||
function VueNodeViewRenderer(component, options) { | ||
return (props) => { | ||
// try to get the parent component | ||
// this is important for vue devtools to show the component hierarchy correctly | ||
// maybe it’s `undefined` because <editor-content> isn’t rendered yet | ||
if (!props.editor.contentComponent) { | ||
return {}; | ||
} | ||
return new VueNodeView(component, props, options); | ||
}; | ||
} | ||
export { BubbleMenu, Editor, EditorContent, FloatingMenu, NodeViewContent, NodeViewWrapper, VueNodeViewRenderer, VueRenderer, nodeViewProps, useEditor }; | ||
//# sourceMappingURL=index.js.map | ||
// src/index.ts | ||
export * from "@tiptap/core"; | ||
export { | ||
BubbleMenu, | ||
Editor, | ||
EditorContent, | ||
FloatingMenu, | ||
NodeViewContent, | ||
NodeViewWrapper, | ||
VueNodeViewRenderer, | ||
VueRenderer, | ||
nodeViewProps, | ||
useEditor | ||
}; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@tiptap/vue-3", | ||
"description": "Vue components for tiptap", | ||
"version": "3.0.0-next.0", | ||
"version": "3.0.0-next.1", | ||
"homepage": "https://tiptap.dev", | ||
@@ -17,3 +17,3 @@ "keywords": [ | ||
".": { | ||
"types": "./dist/packages/vue-3/src/index.d.ts", | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.js", | ||
@@ -25,4 +25,3 @@ "require": "./dist/index.cjs" | ||
"module": "dist/index.js", | ||
"umd": "dist/index.umd.js", | ||
"types": "dist/packages/vue-3/src/index.d.ts", | ||
"types": "dist/index.d.ts", | ||
"type": "module", | ||
@@ -34,13 +33,13 @@ "files": [ | ||
"dependencies": { | ||
"@tiptap/extension-bubble-menu": "^3.0.0-next.0", | ||
"@tiptap/extension-floating-menu": "^3.0.0-next.0" | ||
"@tiptap/extension-bubble-menu": "^3.0.0-next.1", | ||
"@tiptap/extension-floating-menu": "^3.0.0-next.1" | ||
}, | ||
"devDependencies": { | ||
"@tiptap/core": "^3.0.0-next.0", | ||
"@tiptap/pm": "^3.0.0-next.0", | ||
"@tiptap/core": "^3.0.0-next.1", | ||
"@tiptap/pm": "^3.0.0-next.1", | ||
"vue": "^3.0.0" | ||
}, | ||
"peerDependencies": { | ||
"@tiptap/core": "^3.0.0-next.0", | ||
"@tiptap/pm": "^3.0.0-next.0", | ||
"@tiptap/core": "^3.0.0-next.1", | ||
"@tiptap/pm": "^3.0.0-next.1", | ||
"vue": "^3.0.0" | ||
@@ -55,5 +54,4 @@ }, | ||
"scripts": { | ||
"clean": "rm -rf dist", | ||
"build": "npm run clean && rollup -c" | ||
"build": "tsup" | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable react-hooks/rules-of-hooks */ | ||
import { Editor as CoreEditor, EditorOptions } from '@tiptap/core' | ||
@@ -2,0 +3,0 @@ import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state' |
@@ -224,5 +224,10 @@ import { | ||
} | ||
// check for class-component and normalize if neccessary | ||
const normalizedComponent = typeof component === 'function' && '__vccOpts' in component | ||
// eslint-disable-next-line no-underscore-dangle | ||
? component.__vccOpts as Component | ||
: component | ||
return new VueNodeView(component, props, options) as unknown as ProseMirrorNodeView | ||
return new VueNodeView(normalizedComponent, props, options) as unknown as ProseMirrorNodeView | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
128019
18
2064
1