@tiptap/vue-3
Advanced tools
Comparing version
@@ -1,11 +0,219 @@ | ||
export * from './BubbleMenu.js'; | ||
export { Editor } from './Editor.js'; | ||
export * from './EditorContent.js'; | ||
export * from './FloatingMenu.js'; | ||
export * from './NodeViewContent.js'; | ||
export * from './NodeViewWrapper.js'; | ||
export * from './useEditor.js'; | ||
export * from './VueNodeViewRenderer.js'; | ||
export * from './VueRenderer.js'; | ||
import { Editor as Editor$1, EditorOptions, Storage, MarkViewRendererOptions, MarkViewProps, MarkView, MarkViewRenderer, NodeViewProps, NodeViewRendererOptions, NodeViewRenderer } from '@tiptap/core'; | ||
export * from '@tiptap/core'; | ||
//# sourceMappingURL=index.d.ts.map | ||
import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state'; | ||
import * as vue from 'vue'; | ||
import { AppContext, ComponentInternalInstance, ComponentPublicInstance, PropType, Ref, Component, h } from 'vue'; | ||
import { Node } from '@tiptap/pm/model'; | ||
import { Decoration, DecorationSource } from '@tiptap/pm/view'; | ||
type ContentComponent = ComponentInternalInstance & { | ||
ctx: ComponentPublicInstance; | ||
}; | ||
declare class Editor extends Editor$1 { | ||
private reactiveState; | ||
private reactiveExtensionStorage; | ||
contentComponent: ContentComponent | null; | ||
appContext: AppContext | null; | ||
constructor(options?: Partial<EditorOptions>); | ||
get state(): EditorState; | ||
get storage(): Storage; | ||
/** | ||
* Register a ProseMirror plugin. | ||
*/ | ||
registerPlugin(plugin: Plugin, handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[]): EditorState; | ||
/** | ||
* Unregister a ProseMirror plugin. | ||
*/ | ||
unregisterPlugin(nameOrPluginKey: string | PluginKey): EditorState | undefined; | ||
} | ||
declare const EditorContent: vue.DefineComponent<vue.ExtractPropTypes<{ | ||
editor: { | ||
default: null; | ||
type: PropType<Editor>; | ||
}; | ||
}>, { | ||
rootEl: Ref<Element | undefined, Element | undefined>; | ||
}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{ | ||
editor: { | ||
default: null; | ||
type: PropType<Editor>; | ||
}; | ||
}>> & Readonly<{}>, { | ||
editor: Editor; | ||
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>; | ||
declare const NodeViewContent: vue.DefineComponent<vue.ExtractPropTypes<{ | ||
as: { | ||
type: StringConstructor; | ||
default: string; | ||
}; | ||
}>, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{ | ||
as: { | ||
type: StringConstructor; | ||
default: string; | ||
}; | ||
}>> & Readonly<{}>, { | ||
as: string; | ||
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>; | ||
declare const NodeViewWrapper: vue.DefineComponent<vue.ExtractPropTypes<{ | ||
as: { | ||
type: StringConstructor; | ||
default: string; | ||
}; | ||
}>, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{ | ||
as: { | ||
type: StringConstructor; | ||
default: string; | ||
}; | ||
}>> & Readonly<{}>, { | ||
as: string; | ||
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>; | ||
declare const useEditor: (options?: Partial<EditorOptions>) => vue.ShallowRef<Editor | undefined, Editor | undefined>; | ||
interface VueRendererOptions { | ||
editor: Editor$1; | ||
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. | ||
*/ | ||
declare class VueRenderer { | ||
renderedComponent: RenderedComponent; | ||
editor: Editor; | ||
component: Component; | ||
el: Element | null; | ||
props: Record<string, any>; | ||
constructor(component: Component, { props, editor }: VueRendererOptions); | ||
get element(): Element | null; | ||
get ref(): any; | ||
renderComponent(): { | ||
vNode: vue.VNode<vue.RendererNode, vue.RendererElement, { | ||
[key: string]: any; | ||
}>; | ||
destroy: () => void; | ||
el: Element | null; | ||
}; | ||
updateProps(props?: Record<string, any>): void; | ||
destroy(): void; | ||
} | ||
interface VueMarkViewRendererOptions extends MarkViewRendererOptions { | ||
as?: string; | ||
className?: string; | ||
attrs?: { | ||
[key: string]: string; | ||
}; | ||
} | ||
declare const markViewProps: { | ||
editor: { | ||
type: PropType<MarkViewProps["editor"]>; | ||
required: true; | ||
}; | ||
mark: { | ||
type: PropType<MarkViewProps["mark"]>; | ||
required: true; | ||
}; | ||
extension: { | ||
type: PropType<MarkViewProps["extension"]>; | ||
required: true; | ||
}; | ||
inline: { | ||
type: PropType<MarkViewProps["inline"]>; | ||
required: true; | ||
}; | ||
view: { | ||
type: PropType<MarkViewProps["view"]>; | ||
required: true; | ||
}; | ||
}; | ||
declare const MarkViewContent: vue.DefineComponent<vue.ExtractPropTypes<{ | ||
as: { | ||
type: StringConstructor; | ||
default: string; | ||
}; | ||
}>, {}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{ | ||
as: { | ||
type: StringConstructor; | ||
default: string; | ||
}; | ||
}>> & Readonly<{}>, { | ||
as: string; | ||
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>; | ||
declare class VueMarkView extends MarkView<Component, VueMarkViewRendererOptions> { | ||
renderer: VueRenderer; | ||
constructor(component: Component, props: MarkViewProps, options?: Partial<VueMarkViewRendererOptions>); | ||
get dom(): HTMLElement; | ||
get contentDOM(): HTMLElement | null; | ||
destroy(): void; | ||
} | ||
declare function VueMarkViewRenderer(component: Component, options?: Partial<VueMarkViewRendererOptions>): MarkViewRenderer; | ||
declare const nodeViewProps: { | ||
editor: { | ||
type: PropType<NodeViewProps["editor"]>; | ||
required: true; | ||
}; | ||
node: { | ||
type: PropType<NodeViewProps["node"]>; | ||
required: true; | ||
}; | ||
decorations: { | ||
type: PropType<NodeViewProps["decorations"]>; | ||
required: true; | ||
}; | ||
selected: { | ||
type: PropType<NodeViewProps["selected"]>; | ||
required: true; | ||
}; | ||
extension: { | ||
type: PropType<NodeViewProps["extension"]>; | ||
required: true; | ||
}; | ||
getPos: { | ||
type: PropType<NodeViewProps["getPos"]>; | ||
required: true; | ||
}; | ||
updateAttributes: { | ||
type: PropType<NodeViewProps["updateAttributes"]>; | ||
required: true; | ||
}; | ||
deleteNode: { | ||
type: PropType<NodeViewProps["deleteNode"]>; | ||
required: true; | ||
}; | ||
view: { | ||
type: PropType<NodeViewProps["view"]>; | ||
required: true; | ||
}; | ||
innerDecorations: { | ||
type: PropType<NodeViewProps["innerDecorations"]>; | ||
required: true; | ||
}; | ||
HTMLAttributes: { | ||
type: PropType<NodeViewProps["HTMLAttributes"]>; | ||
required: true; | ||
}; | ||
}; | ||
interface VueNodeViewRendererOptions extends NodeViewRendererOptions { | ||
update: ((props: { | ||
oldNode: Node; | ||
oldDecorations: readonly Decoration[]; | ||
oldInnerDecorations: DecorationSource; | ||
newNode: Node; | ||
newDecorations: readonly Decoration[]; | ||
innerDecorations: DecorationSource; | ||
updateProps: () => void; | ||
}) => boolean) | null; | ||
} | ||
declare function VueNodeViewRenderer(component: Component<NodeViewProps>, options?: Partial<VueNodeViewRendererOptions>): NodeViewRenderer; | ||
export { Editor, EditorContent, MarkViewContent, NodeViewContent, NodeViewWrapper, VueMarkView, VueMarkViewRenderer, type VueMarkViewRendererOptions, VueNodeViewRenderer, type VueNodeViewRendererOptions, VueRenderer, type VueRendererOptions, markViewProps, nodeViewProps, useEditor }; |
1042
dist/index.js
@@ -1,553 +0,563 @@ | ||
import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'; | ||
import { defineComponent, ref, onMounted, onBeforeUnmount, h, 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, | ||
}, | ||
tippyOptions: { | ||
type: Object, | ||
default: () => ({}), | ||
}, | ||
shouldShow: { | ||
type: Function, | ||
default: null, | ||
}, | ||
}, | ||
setup(props, { slots }) { | ||
const root = ref(null); | ||
onMounted(() => { | ||
const { updateDelay, editor, pluginKey, shouldShow, tippyOptions, } = props; | ||
editor.registerPlugin(BubbleMenuPlugin({ | ||
updateDelay, | ||
editor, | ||
element: root.value, | ||
pluginKey, | ||
shouldShow, | ||
tippyOptions, | ||
})); | ||
// 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) { | ||
value = newValue; | ||
requestAnimationFrame(() => { | ||
requestAnimationFrame(() => { | ||
trigger(); | ||
}); | ||
}); | ||
onBeforeUnmount(() => { | ||
const { pluginKey, editor } = props; | ||
editor.unregisterPlugin(pluginKey); | ||
}); | ||
return () => { var _a; return h('div', { ref: root }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); }; | ||
}, | ||
}); | ||
/* eslint-disable react-hooks/rules-of-hooks */ | ||
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(); | ||
}); | ||
}); | ||
}, | ||
}; | ||
} | ||
}; | ||
}); | ||
} | ||
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; | ||
}); | ||
} | ||
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 markRaw(this); // eslint-disable-line | ||
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) { | ||
const nextState = super.registerPlugin(plugin, handlePlugins); | ||
if (this.reactiveState) { | ||
this.reactiveState.value = nextState; | ||
} | ||
get state() { | ||
return this.reactiveState ? this.reactiveState.value : this.view.state; | ||
return nextState; | ||
} | ||
/** | ||
* Unregister a ProseMirror plugin. | ||
*/ | ||
unregisterPlugin(nameOrPluginKey) { | ||
const nextState = super.unregisterPlugin(nameOrPluginKey); | ||
if (this.reactiveState && nextState) { | ||
this.reactiveState.value = nextState; | ||
} | ||
get storage() { | ||
return this.reactiveExtensionStorage ? this.reactiveExtensionStorage.value : super.storage; | ||
return nextState; | ||
} | ||
}; | ||
// src/EditorContent.ts | ||
import { defineComponent, getCurrentInstance, h, nextTick, onBeforeUnmount, ref, unref, watchEffect } from "vue"; | ||
var EditorContent = defineComponent({ | ||
name: "EditorContent", | ||
props: { | ||
editor: { | ||
default: null, | ||
type: Object | ||
} | ||
/** | ||
* Register a ProseMirror plugin. | ||
*/ | ||
registerPlugin(plugin, handlePlugins) { | ||
const nextState = super.registerPlugin(plugin, handlePlugins); | ||
if (this.reactiveState) { | ||
this.reactiveState.value = nextState; | ||
} | ||
return nextState; | ||
} | ||
/** | ||
* Unregister a ProseMirror plugin. | ||
*/ | ||
unregisterPlugin(nameOrPluginKey) { | ||
const nextState = super.unregisterPlugin(nameOrPluginKey); | ||
if (this.reactiveState && nextState) { | ||
this.reactiveState.value = nextState; | ||
} | ||
return nextState; | ||
} | ||
} | ||
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(); | ||
}); | ||
} | ||
}, | ||
setup(props) { | ||
const rootEl = ref(); | ||
const instance = getCurrentInstance(); | ||
watchEffect(() => { | ||
const editor = props.editor; | ||
if (editor && editor.options.element && rootEl.value) { | ||
nextTick(() => { | ||
var _a; | ||
if (!rootEl.value || !((_a = editor.options.element) == null ? void 0 : _a.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; | ||
} | ||
editor.contentComponent = null; | ||
editor.appContext = null; | ||
}); | ||
return { rootEl }; | ||
}, | ||
render() { | ||
return h('div', { | ||
ref: (el) => { this.rootEl = el; }, | ||
}); | ||
}, | ||
} | ||
}); | ||
onBeforeUnmount(() => { | ||
const editor = props.editor; | ||
if (!editor) { | ||
return; | ||
} | ||
editor.contentComponent = null; | ||
editor.appContext = null; | ||
}); | ||
return { rootEl }; | ||
}, | ||
render() { | ||
return h("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, | ||
}, | ||
tippyOptions: { | ||
type: Object, | ||
default: () => ({}), | ||
}, | ||
shouldShow: { | ||
type: Function, | ||
default: null, | ||
}, | ||
}, | ||
setup(props, { slots }) { | ||
const root = ref(null); | ||
onMounted(() => { | ||
const { pluginKey, editor, tippyOptions, shouldShow, } = props; | ||
editor.registerPlugin(FloatingMenuPlugin({ | ||
pluginKey, | ||
editor, | ||
element: root.value, | ||
tippyOptions, | ||
shouldShow, | ||
})); | ||
}); | ||
onBeforeUnmount(() => { | ||
const { pluginKey, editor } = props; | ||
editor.unregisterPlugin(pluginKey); | ||
}); | ||
return () => { var _a; return h('div', { ref: root }, (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)); }; | ||
}, | ||
// src/NodeViewContent.ts | ||
import { defineComponent as defineComponent2, h as h2 } from "vue"; | ||
var NodeViewContent = defineComponent2({ | ||
name: "NodeViewContent", | ||
props: { | ||
as: { | ||
type: String, | ||
default: "div" | ||
} | ||
}, | ||
render() { | ||
return h2(this.as, { | ||
style: { | ||
whiteSpace: "pre-wrap" | ||
}, | ||
"data-node-view-content": "" | ||
}); | ||
} | ||
}); | ||
const NodeViewContent = defineComponent({ | ||
name: 'NodeViewContent', | ||
props: { | ||
as: { | ||
type: String, | ||
default: 'div', | ||
// src/NodeViewWrapper.ts | ||
import { defineComponent as defineComponent3, h as h3 } from "vue"; | ||
var NodeViewWrapper = defineComponent3({ | ||
name: "NodeViewWrapper", | ||
props: { | ||
as: { | ||
type: String, | ||
default: "div" | ||
} | ||
}, | ||
inject: ["onDragStart", "decorationClasses"], | ||
render() { | ||
var _a, _b; | ||
return h3( | ||
this.as, | ||
{ | ||
// @ts-ignore | ||
class: this.decorationClasses, | ||
style: { | ||
whiteSpace: "normal" | ||
}, | ||
}, | ||
render() { | ||
return h(this.as, { | ||
style: { | ||
whiteSpace: 'pre-wrap', | ||
}, | ||
'data-node-view-content': '', | ||
}); | ||
}, | ||
"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 NodeViewWrapper = defineComponent({ | ||
name: 'NodeViewWrapper', | ||
props: { | ||
as: { | ||
type: String, | ||
default: 'div', | ||
}, | ||
}, | ||
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)); | ||
}, | ||
}); | ||
const useEditor = (options = {}) => { | ||
const editor = shallowRef(); | ||
onMounted(() => { | ||
editor.value = new Editor(options); | ||
}); | ||
onBeforeUnmount(() => { | ||
var _a, _b, _c; | ||
// Cloning root node (and its children) to avoid content being lost by destroy | ||
const nodes = (_a = editor.value) === null || _a === void 0 ? void 0 : _a.options.element; | ||
const newEl = nodes === null || nodes === void 0 ? void 0 : nodes.cloneNode(true); | ||
(_b = nodes === null || nodes === void 0 ? void 0 : nodes.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(newEl, nodes); | ||
(_c = editor.value) === null || _c === void 0 ? void 0 : _c.destroy(); | ||
}); | ||
return editor; | ||
// src/useEditor.ts | ||
import { onBeforeUnmount as onBeforeUnmount2, onMounted, shallowRef } from "vue"; | ||
var useEditor = (options = {}) => { | ||
const editor = shallowRef(); | ||
onMounted(() => { | ||
editor.value = new Editor(options); | ||
}); | ||
onBeforeUnmount2(() => { | ||
var _a, _b, _c; | ||
const nodes = (_a = editor.value) == null ? void 0 : _a.options.element; | ||
const newEl = nodes == null ? void 0 : nodes.cloneNode(true); | ||
(_b = nodes == null ? void 0 : nodes.parentNode) == null ? void 0 : _b.replaceChild(newEl, nodes); | ||
(_c = editor.value) == null ? void 0 : _c.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/VueMarkViewRenderer.ts | ||
import { MarkView } from "@tiptap/core"; | ||
import { defineComponent as defineComponent4, h as h5 } from "vue"; | ||
// src/VueRenderer.ts | ||
import { h as h4, 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 = h4(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 }; | ||
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(); | ||
} | ||
}; | ||
// src/VueMarkViewRenderer.ts | ||
var markViewProps = { | ||
editor: { | ||
type: Object, | ||
required: true | ||
}, | ||
mark: { | ||
type: Object, | ||
required: true | ||
}, | ||
extension: { | ||
type: Object, | ||
required: true | ||
}, | ||
inline: { | ||
type: Boolean, | ||
required: true | ||
}, | ||
view: { | ||
type: Object, | ||
required: true | ||
} | ||
}; | ||
var MarkViewContent = defineComponent4({ | ||
name: "MarkViewContent", | ||
props: { | ||
as: { | ||
type: String, | ||
default: "span" | ||
} | ||
updateProps(props = {}) { | ||
Object.entries(props).forEach(([key, value]) => { | ||
this.props[key] = value; | ||
}, | ||
render() { | ||
return h5(this.as, { | ||
style: { | ||
whiteSpace: "inherit" | ||
}, | ||
"data-mark-view-content": "" | ||
}); | ||
} | ||
}); | ||
var VueMarkView = class extends MarkView { | ||
constructor(component, props, options) { | ||
super(component, props, options); | ||
const extendedComponent = defineComponent4({ | ||
extends: { ...component }, | ||
props: Object.keys(props), | ||
template: this.component.template, | ||
setup: (reactiveProps) => { | ||
var _a; | ||
return (_a = component.setup) == null ? void 0 : _a.call(component, reactiveProps, { | ||
expose: () => void 0 | ||
}); | ||
this.renderComponent(); | ||
}, | ||
// Add support for scoped styles | ||
__scopeId: component.__scopeId, | ||
__cssModules: component.__cssModules, | ||
__name: component.__name, | ||
__file: component.__file | ||
}); | ||
this.renderer = new VueRenderer(extendedComponent, { | ||
editor: this.editor, | ||
props | ||
}); | ||
} | ||
get dom() { | ||
return this.renderer.element; | ||
} | ||
get contentDOM() { | ||
return this.dom.querySelector("[data-mark-view-content]"); | ||
} | ||
destroy() { | ||
this.renderer.destroy(); | ||
} | ||
}; | ||
function VueMarkViewRenderer(component, options = {}) { | ||
return (props) => { | ||
if (!props.editor.contentComponent) { | ||
return {}; | ||
} | ||
destroy() { | ||
this.renderedComponent.destroy(); | ||
} | ||
return new VueMarkView(component, props, options); | ||
}; | ||
} | ||
/* eslint-disable no-underscore-dangle */ | ||
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, | ||
}, | ||
view: { | ||
type: Object, | ||
required: true, | ||
}, | ||
innerDecorations: { | ||
type: Object, | ||
required: true, | ||
}, | ||
HTMLAttributes: { | ||
type: Object, | ||
required: true, | ||
}, | ||
// src/VueNodeViewRenderer.ts | ||
import { NodeView } from "@tiptap/core"; | ||
import { defineComponent as defineComponent5, provide, ref as ref2 } from "vue"; | ||
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 | ||
}, | ||
view: { | ||
type: Object, | ||
required: true | ||
}, | ||
innerDecorations: { | ||
type: Object, | ||
required: true | ||
}, | ||
HTMLAttributes: { | ||
type: Object, | ||
required: true | ||
} | ||
}; | ||
class VueNodeView extends NodeView { | ||
mount() { | ||
const props = { | ||
editor: this.editor, | ||
node: this.node, | ||
decorations: this.decorations, | ||
innerDecorations: this.innerDecorations, | ||
view: this.view, | ||
selected: false, | ||
extension: this.extension, | ||
HTMLAttributes: this.HTMLAttributes, | ||
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, | ||
innerDecorations: this.innerDecorations, | ||
view: this.view, | ||
selected: false, | ||
extension: this.extension, | ||
HTMLAttributes: this.HTMLAttributes, | ||
getPos: () => this.getPos(), | ||
updateAttributes: (attributes = {}) => this.updateAttributes(attributes), | ||
deleteNode: () => this.deleteNode() | ||
}; | ||
const onDragStart = this.onDragStart.bind(this); | ||
this.decorationClasses = ref2(this.getDecorationClasses()); | ||
const extendedComponent = defineComponent5({ | ||
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.handleSelectionUpdate = this.handleSelectionUpdate.bind(this); | ||
this.editor.on('selectionUpdate', this.handleSelectionUpdate); | ||
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.handleSelectionUpdate = this.handleSelectionUpdate.bind(this); | ||
this.editor.on("selectionUpdate", this.handleSelectionUpdate); | ||
this.renderer = new VueRenderer(extendedComponent, { | ||
editor: this.editor, | ||
props | ||
}); | ||
} | ||
/** | ||
* Return the DOM element. | ||
* This is the element that will be used to display the 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 the DOM element. | ||
* This is the element that will be used to display the 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; | ||
} | ||
/** | ||
* Return the content DOM element. | ||
* This is the element that will be used to display the rich-text content of the node. | ||
*/ | ||
get contentDOM() { | ||
if (this.node.isLeaf) { | ||
return null; | ||
} | ||
/** | ||
* Return the content DOM element. | ||
* This is the element that will be used to display the rich-text content of the node. | ||
*/ | ||
get contentDOM() { | ||
if (this.node.isLeaf) { | ||
return null; | ||
} | ||
return this.dom.querySelector('[data-node-view-content]'); | ||
return this.dom.querySelector("[data-node-view-content]"); | ||
} | ||
/** | ||
* On editor selection update, check if the node is selected. | ||
* If it is, call `selectNode`, otherwise call `deselectNode`. | ||
*/ | ||
handleSelectionUpdate() { | ||
const { from, to } = this.editor.state.selection; | ||
const pos = this.getPos(); | ||
if (typeof pos !== "number") { | ||
return; | ||
} | ||
/** | ||
* On editor selection update, check if the node is selected. | ||
* If it is, call `selectNode`, otherwise call `deselectNode`. | ||
*/ | ||
handleSelectionUpdate() { | ||
const { from, to } = this.editor.state.selection; | ||
const pos = this.getPos(); | ||
if (typeof pos !== 'number') { | ||
return; | ||
} | ||
if (from <= pos && to >= pos + this.node.nodeSize) { | ||
if (this.renderer.props.selected) { | ||
return; | ||
} | ||
this.selectNode(); | ||
} | ||
else { | ||
if (!this.renderer.props.selected) { | ||
return; | ||
} | ||
this.deselectNode(); | ||
} | ||
if (from <= pos && to >= pos + this.node.nodeSize) { | ||
if (this.renderer.props.selected) { | ||
return; | ||
} | ||
this.selectNode(); | ||
} else { | ||
if (!this.renderer.props.selected) { | ||
return; | ||
} | ||
this.deselectNode(); | ||
} | ||
/** | ||
* On update, update the React component. | ||
* To prevent unnecessary updates, the `update` option can be used. | ||
*/ | ||
update(node, decorations, innerDecorations) { | ||
const rerenderComponent = (props) => { | ||
this.decorationClasses.value = this.getDecorationClasses(); | ||
this.renderer.updateProps(props); | ||
}; | ||
if (typeof this.options.update === 'function') { | ||
const oldNode = this.node; | ||
const oldDecorations = this.decorations; | ||
const oldInnerDecorations = this.innerDecorations; | ||
this.node = node; | ||
this.decorations = decorations; | ||
this.innerDecorations = innerDecorations; | ||
return this.options.update({ | ||
oldNode, | ||
oldDecorations, | ||
newNode: node, | ||
newDecorations: decorations, | ||
oldInnerDecorations, | ||
innerDecorations, | ||
updateProps: () => rerenderComponent({ node, decorations, innerDecorations }), | ||
}); | ||
} | ||
if (node.type !== this.node.type) { | ||
return false; | ||
} | ||
if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) { | ||
return true; | ||
} | ||
this.node = node; | ||
this.decorations = decorations; | ||
this.innerDecorations = innerDecorations; | ||
rerenderComponent({ node, decorations, innerDecorations }); | ||
return true; | ||
} | ||
/** | ||
* On update, update the React component. | ||
* To prevent unnecessary updates, the `update` option can be used. | ||
*/ | ||
update(node, decorations, innerDecorations) { | ||
const rerenderComponent = (props) => { | ||
this.decorationClasses.value = this.getDecorationClasses(); | ||
this.renderer.updateProps(props); | ||
}; | ||
if (typeof this.options.update === "function") { | ||
const oldNode = this.node; | ||
const oldDecorations = this.decorations; | ||
const oldInnerDecorations = this.innerDecorations; | ||
this.node = node; | ||
this.decorations = decorations; | ||
this.innerDecorations = innerDecorations; | ||
return this.options.update({ | ||
oldNode, | ||
oldDecorations, | ||
newNode: node, | ||
newDecorations: decorations, | ||
oldInnerDecorations, | ||
innerDecorations, | ||
updateProps: () => rerenderComponent({ node, decorations, innerDecorations }) | ||
}); | ||
} | ||
/** | ||
* Select the node. | ||
* Add the `selected` prop and the `ProseMirror-selectednode` class. | ||
*/ | ||
selectNode() { | ||
this.renderer.updateProps({ | ||
selected: true, | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add('ProseMirror-selectednode'); | ||
} | ||
if (node.type !== this.node.type) { | ||
return false; | ||
} | ||
/** | ||
* Deselect the node. | ||
* Remove the `selected` prop and the `ProseMirror-selectednode` class. | ||
*/ | ||
deselectNode() { | ||
this.renderer.updateProps({ | ||
selected: false, | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove('ProseMirror-selectednode'); | ||
} | ||
if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) { | ||
return true; | ||
} | ||
getDecorationClasses() { | ||
return (this.decorations | ||
// @ts-ignore | ||
.map(item => item.type.attrs.class) | ||
.flat() | ||
.join(' ')); | ||
this.node = node; | ||
this.decorations = decorations; | ||
this.innerDecorations = innerDecorations; | ||
rerenderComponent({ node, decorations, innerDecorations }); | ||
return true; | ||
} | ||
/** | ||
* Select the node. | ||
* Add the `selected` prop and the `ProseMirror-selectednode` class. | ||
*/ | ||
selectNode() { | ||
this.renderer.updateProps({ | ||
selected: true | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add("ProseMirror-selectednode"); | ||
} | ||
destroy() { | ||
this.renderer.destroy(); | ||
this.editor.off('selectionUpdate', this.handleSelectionUpdate); | ||
} | ||
/** | ||
* Deselect the node. | ||
* Remove the `selected` prop and the `ProseMirror-selectednode` class. | ||
*/ | ||
deselectNode() { | ||
this.renderer.updateProps({ | ||
selected: false | ||
}); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove("ProseMirror-selectednode"); | ||
} | ||
} | ||
} | ||
getDecorationClasses() { | ||
return this.decorations.map((item) => item.type.attrs.class).flat().join(" "); | ||
} | ||
destroy() { | ||
this.renderer.destroy(); | ||
this.editor.off("selectionUpdate", this.handleSelectionUpdate); | ||
} | ||
}; | ||
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 {}; | ||
} | ||
// check for class-component and normalize if neccessary | ||
const normalizedComponent = typeof component === 'function' && '__vccOpts' in component | ||
? component.__vccOpts | ||
: component; | ||
return new VueNodeView(normalizedComponent, props, 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); | ||
}; | ||
} | ||
export { BubbleMenu, Editor, EditorContent, FloatingMenu, NodeViewContent, NodeViewWrapper, VueNodeViewRenderer, VueRenderer, nodeViewProps, useEditor }; | ||
//# sourceMappingURL=index.js.map | ||
// src/index.ts | ||
export * from "@tiptap/core"; | ||
export { | ||
Editor, | ||
EditorContent, | ||
MarkViewContent, | ||
NodeViewContent, | ||
NodeViewWrapper, | ||
VueMarkView, | ||
VueMarkViewRenderer, | ||
VueNodeViewRenderer, | ||
VueRenderer, | ||
markViewProps, | ||
nodeViewProps, | ||
useEditor | ||
}; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@tiptap/vue-3", | ||
"description": "Vue components for tiptap", | ||
"version": "2.11.7", | ||
"version": "3.0.0-beta.0", | ||
"homepage": "https://tiptap.dev", | ||
@@ -17,5 +17,16 @@ "keywords": [ | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"types": { | ||
"import": "./dist/index.d.ts", | ||
"require": "./dist/index.d.cts" | ||
}, | ||
"import": "./dist/index.js", | ||
"require": "./dist/index.cjs" | ||
}, | ||
"./menus": { | ||
"types": { | ||
"import": "./dist/menus/index.d.ts", | ||
"require": "./dist/menus/index.d.cts" | ||
}, | ||
"import": "./dist/menus/index.js", | ||
"require": "./dist/menus/index.cjs" | ||
} | ||
@@ -25,3 +36,2 @@ }, | ||
"module": "dist/index.js", | ||
"umd": "dist/index.umd.js", | ||
"types": "dist/index.d.ts", | ||
@@ -33,15 +43,16 @@ "type": "module", | ||
], | ||
"dependencies": { | ||
"@tiptap/extension-bubble-menu": "^2.11.7", | ||
"@tiptap/extension-floating-menu": "^2.11.7" | ||
}, | ||
"devDependencies": { | ||
"@tiptap/core": "^2.11.7", | ||
"@tiptap/pm": "^2.11.7", | ||
"vue": "^3.0.0" | ||
"@tiptap/core": "^3.0.0-beta.0", | ||
"@tiptap/pm": "^3.0.0-beta.0", | ||
"vue": "^3.5.13" | ||
}, | ||
"optionalDependencies": { | ||
"@tiptap/extension-bubble-menu": "^3.0.0-beta.0", | ||
"@tiptap/extension-floating-menu": "^3.0.0-beta.0" | ||
}, | ||
"peerDependencies": { | ||
"@tiptap/core": "^2.7.0", | ||
"@tiptap/pm": "^2.7.0", | ||
"vue": "^3.0.0" | ||
"@tiptap/core": "^3.0.0-beta.0", | ||
"@tiptap/pm": "^3.0.0-beta.0", | ||
"vue": "^3.0.0", | ||
"@floating-ui/dom": "^1.0.0" | ||
}, | ||
@@ -55,5 +66,5 @@ "repository": { | ||
"scripts": { | ||
"clean": "rm -rf dist", | ||
"build": "npm run clean && rollup -c" | ||
"build": "tsup", | ||
"lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/" | ||
} | ||
} | ||
} |
# @tiptap/vue-3 | ||
[](https://www.npmjs.com/package/@tiptap/vue-3) | ||
@@ -8,8 +9,11 @@ [](https://npmcharts.com/compare/tiptap?minimal=true) | ||
## Introduction | ||
Tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) โ a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*. | ||
Tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) โ a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as _New York Times_, _The Guardian_ or _Atlassian_. | ||
## Official Documentation | ||
Documentation can be found on the [Tiptap website](https://tiptap.dev). | ||
## License | ||
Tiptap is open sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap/blob/main/LICENSE.md). |
/* eslint-disable react-hooks/rules-of-hooks */ | ||
import { Editor as CoreEditor, EditorOptions } from '@tiptap/core' | ||
import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state' | ||
import { | ||
AppContext, | ||
ComponentInternalInstance, | ||
ComponentPublicInstance, | ||
customRef, | ||
markRaw, | ||
Ref, | ||
} from 'vue' | ||
import type { EditorOptions, Storage } from '@tiptap/core' | ||
import { Editor as CoreEditor } from '@tiptap/core' | ||
import type { EditorState, Plugin, PluginKey } from '@tiptap/pm/state' | ||
import type { AppContext, ComponentInternalInstance, ComponentPublicInstance, Ref } from 'vue' | ||
import { customRef, markRaw } from 'vue' | ||
@@ -42,3 +37,3 @@ function useDebouncedRef<T>(value: T) { | ||
private reactiveExtensionStorage: Ref<Record<string, any>> | ||
private reactiveExtensionStorage: Ref<Storage> | ||
@@ -45,0 +40,0 @@ public contentComponent: ContentComponent | null = null |
@@ -1,15 +0,5 @@ | ||
import { | ||
defineComponent, | ||
getCurrentInstance, | ||
h, | ||
nextTick, | ||
onBeforeUnmount, | ||
PropType, | ||
Ref, | ||
ref, | ||
unref, | ||
watchEffect, | ||
} from 'vue' | ||
import type { PropType, Ref } from 'vue' | ||
import { defineComponent, getCurrentInstance, h, nextTick, onBeforeUnmount, ref, unref, watchEffect } from 'vue' | ||
import { Editor } from './Editor.js' | ||
import type { Editor } from './Editor.js' | ||
@@ -35,6 +25,7 @@ export const EditorContent = defineComponent({ | ||
nextTick(() => { | ||
if (!rootEl.value || !editor.options.element.firstChild) { | ||
if (!rootEl.value || !editor.options.element?.firstChild) { | ||
return | ||
} | ||
// TODO using the new editor.mount method might allow us to remove this | ||
const element = unref(rootEl.value) | ||
@@ -81,9 +72,8 @@ | ||
render() { | ||
return h( | ||
'div', | ||
{ | ||
ref: (el: any) => { this.rootEl = el }, | ||
return h('div', { | ||
ref: (el: any) => { | ||
this.rootEl = el | ||
}, | ||
) | ||
}) | ||
}, | ||
}) |
@@ -1,10 +0,9 @@ | ||
export * from './BubbleMenu.js' | ||
export { Editor } from './Editor.js' | ||
export * from './EditorContent.js' | ||
export * from './FloatingMenu.js' | ||
export * from './NodeViewContent.js' | ||
export * from './NodeViewWrapper.js' | ||
export * from './useEditor.js' | ||
export * from './VueMarkViewRenderer.js' | ||
export * from './VueNodeViewRenderer.js' | ||
export * from './VueRenderer.js' | ||
export * from '@tiptap/core' |
@@ -1,2 +0,2 @@ | ||
import { EditorOptions } from '@tiptap/core' | ||
import type { EditorOptions } from '@tiptap/core' | ||
import { onBeforeUnmount, onMounted, shallowRef } from 'vue' | ||
@@ -3,0 +3,0 @@ |
/* eslint-disable no-underscore-dangle */ | ||
import { | ||
DecorationWithType, | ||
NodeView, | ||
NodeViewProps, | ||
NodeViewRenderer, | ||
NodeViewRendererOptions, | ||
} from '@tiptap/core' | ||
import { Node as ProseMirrorNode } from '@tiptap/pm/model' | ||
import { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view' | ||
import { | ||
Component, defineComponent, PropType, provide, Ref, ref, | ||
} from 'vue' | ||
import type { DecorationWithType, NodeViewProps, NodeViewRenderer, NodeViewRendererOptions } from '@tiptap/core' | ||
import { NodeView } from '@tiptap/core' | ||
import type { Node as ProseMirrorNode } from '@tiptap/pm/model' | ||
import type { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view' | ||
import type { Component, PropType, Ref } from 'vue' | ||
import { defineComponent, provide, ref } from 'vue' | ||
import { Editor } from './Editor.js' | ||
import type { Editor } from './Editor.js' | ||
import { VueRenderer } from './VueRenderer.js' | ||
@@ -68,11 +62,11 @@ | ||
| ((props: { | ||
oldNode: ProseMirrorNode; | ||
oldDecorations: readonly Decoration[]; | ||
oldInnerDecorations: DecorationSource; | ||
newNode: ProseMirrorNode; | ||
newDecorations: readonly Decoration[]; | ||
innerDecorations: DecorationSource; | ||
updateProps: () => void; | ||
oldNode: ProseMirrorNode | ||
oldDecorations: readonly Decoration[] | ||
oldInnerDecorations: DecorationSource | ||
newNode: ProseMirrorNode | ||
newDecorations: readonly Decoration[] | ||
innerDecorations: DecorationSource | ||
updateProps: () => void | ||
}) => boolean) | ||
| null; | ||
| null | ||
} | ||
@@ -197,7 +191,3 @@ | ||
*/ | ||
update( | ||
node: ProseMirrorNode, | ||
decorations: readonly Decoration[], | ||
innerDecorations: DecorationSource, | ||
): boolean { | ||
update(node: ProseMirrorNode, decorations: readonly Decoration[], innerDecorations: DecorationSource): boolean { | ||
const rerenderComponent = (props?: Record<string, any>) => { | ||
@@ -299,5 +289,4 @@ this.decorationClasses.value = this.getDecorationClasses() | ||
// check for class-component and normalize if neccessary | ||
const normalizedComponent = typeof component === 'function' && '__vccOpts' in component | ||
? (component.__vccOpts as Component) | ||
: component | ||
const normalizedComponent = | ||
typeof component === 'function' && '__vccOpts' in component ? (component.__vccOpts as Component) : component | ||
@@ -304,0 +293,0 @@ return new VueNodeView(normalizedComponent, props, options) |
@@ -1,19 +0,18 @@ | ||
import { Editor } from '@tiptap/core' | ||
import { | ||
Component, DefineComponent, h, markRaw, reactive, render, | ||
} from 'vue' | ||
import type { Editor } from '@tiptap/core' | ||
import type { Component, DefineComponent } from 'vue' | ||
import { h, markRaw, reactive, render } from 'vue' | ||
import { Editor as ExtendedEditor } from './Editor.js' | ||
import type { Editor as ExtendedEditor } from './Editor.js' | ||
export interface VueRendererOptions { | ||
editor: Editor; | ||
props?: Record<string, any>; | ||
editor: Editor | ||
props?: Record<string, any> | ||
} | ||
type ExtendedVNode = ReturnType<typeof h> | null; | ||
type ExtendedVNode = ReturnType<typeof h> | null | ||
interface RenderedComponent { | ||
vNode: ExtendedVNode; | ||
destroy: () => void; | ||
el: Element | null; | ||
vNode: ExtendedVNode | ||
destroy: () => void | ||
el: Element | null | ||
} | ||
@@ -20,0 +19,0 @@ |
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
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
266300
33.08%3510
34.17%19
26.67%6
20%27
-28.95%1
Infinity%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed