@liveblocks/react-tiptap 3.21.0-exp1 → 3.21.0-exp3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collaboration-liveblocks/cursors.cjs +10 -211
- package/dist/collaboration-liveblocks/cursors.cjs.map +1 -1
- package/dist/collaboration-liveblocks/cursors.js +6 -209
- package/dist/collaboration-liveblocks/cursors.js.map +1 -1
- package/dist/collaboration-liveblocks/plugin.cjs +13 -189
- package/dist/collaboration-liveblocks/plugin.cjs.map +1 -1
- package/dist/collaboration-liveblocks/plugin.js +12 -190
- package/dist/collaboration-liveblocks/plugin.js.map +1 -1
- package/dist/collaboration-liveblocks/schema.cjs +23 -139
- package/dist/collaboration-liveblocks/schema.cjs.map +1 -1
- package/dist/collaboration-liveblocks/schema.js +5 -128
- package/dist/collaboration-liveblocks/schema.js.map +1 -1
- package/dist/comments/CommentsExtension.cjs +3 -2
- package/dist/comments/CommentsExtension.cjs.map +1 -1
- package/dist/comments/CommentsExtension.js +2 -1
- package/dist/comments/CommentsExtension.js.map +1 -1
- package/dist/mentions/MentionExtension.cjs +3 -2
- package/dist/mentions/MentionExtension.cjs.map +1 -1
- package/dist/mentions/MentionExtension.js +2 -1
- package/dist/mentions/MentionExtension.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -6
- package/dist/collaboration-liveblocks/mapping.cjs +0 -218
- package/dist/collaboration-liveblocks/mapping.cjs.map +0 -1
- package/dist/collaboration-liveblocks/mapping.js +0 -207
- package/dist/collaboration-liveblocks/mapping.js.map +0 -1
- package/dist/collaboration-liveblocks/remote.cjs +0 -210
- package/dist/collaboration-liveblocks/remote.cjs.map +0 -1
- package/dist/collaboration-liveblocks/remote.js +0 -207
- package/dist/collaboration-liveblocks/remote.js.map +0 -1
- package/dist/collaboration-liveblocks/steps.cjs +0 -359
- package/dist/collaboration-liveblocks/steps.cjs.map +0 -1
- package/dist/collaboration-liveblocks/steps.js +0 -356
- package/dist/collaboration-liveblocks/steps.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentsExtension.js","sources":["../../src/comments/CommentsExtension.ts"],"sourcesContent":["import { shallow } from \"@liveblocks/core\";\nimport { type Editor, Extension, Mark, mergeAttributes } from \"@tiptap/core\";\nimport type {\n Mark as ProseMirrorMark,\n MarkType,\n Node,\n ResolvedPos,\n} from \"@tiptap/pm/model\";\nimport { Fragment, Slice } from \"@tiptap/pm/model\";\nimport type { EditorState, Transaction } from \"@tiptap/pm/state\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"../collaboration-liveblocks/plugin\";\nimport type { CommentsExtensionStorage, ThreadPluginState } from \"../types\";\nimport {\n LIVEBLOCKS_COMMENT_MARK_TYPE,\n ThreadPluginActions,\n THREADS_ACTIVE_SELECTION_PLUGIN,\n THREADS_PLUGIN_KEY,\n} from \"../types\";\nimport { areSetsEqual } from \"../utils\";\n\ntype ThreadPluginAction = {\n name: ThreadPluginActions;\n data: string[];\n};\n\nexport const FILTERED_THREADS_PLUGIN_KEY = new PluginKey<{\n filteredThreads?: Set<string>;\n}>();\n\nfunction getFilteredThreads(state: EditorState): Set<string> | undefined {\n return FILTERED_THREADS_PLUGIN_KEY.getState(state)?.filteredThreads;\n}\n\nfunction getVisibleThreadIdsFromMarks(\n marks: readonly ProseMirrorMark[],\n markType: MarkType,\n filteredThreads: Set<string> | undefined\n): string[] {\n const ids = new Set<string>();\n for (const mark of marks) {\n if (mark.type !== markType || mark.attrs.orphan) continue;\n const threadId = mark.attrs.threadId as string | undefined;\n if (!threadId) continue;\n if (filteredThreads && !filteredThreads.has(threadId)) continue;\n ids.add(threadId);\n }\n return [...ids];\n}\n\nfunction getVisibleThreadIdsAtPos(\n state: EditorState,\n $pos: ResolvedPos,\n markType: MarkType\n): string[] {\n return getVisibleThreadIdsFromMarks(\n $pos.marks(),\n markType,\n getFilteredThreads(state)\n );\n}\n\nfunction dispatchSetActiveThreadIds(view: EditorView, ids: string[]): void {\n view.dispatch(\n view.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_ACTIVE_THREAD_IDS,\n data: ids,\n } satisfies ThreadPluginAction)\n );\n}\n\nconst Comment = Mark.create({\n name: LIVEBLOCKS_COMMENT_MARK_TYPE,\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n parseHTML: () => {\n return [\n {\n tag: \"span\",\n getAttrs: (node) =>\n node.getAttribute(\"data-lb-thread-id\") !== null && null,\n },\n ];\n },\n addAttributes() {\n // Return an object with attribute configuration\n return {\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-lb-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-lb-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n const filteredThreads = this.editor\n ? FILTERED_THREADS_PLUGIN_KEY.getState(this.editor.state)?.filteredThreads\n : undefined;\n const threadId = (HTMLAttributes as { [\"data-lb-thread-id\"]: string })[\n \"data-lb-thread-id\"\n ];\n if (filteredThreads && !filteredThreads.has(threadId)) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n \"data-hidden\": \"\",\n }),\n ];\n }\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n }),\n ];\n },\n\n /**\n * This plugin tracks the (first) position of each thread mark in the doc and creates a decoration for the selected thread\n */\n addProseMirrorPlugins() {\n const updateState = (\n doc: Node,\n activeThreadIds: string[],\n { scroll }: { scroll: boolean }\n ): ThreadPluginState => {\n const threadPositions = new Map<string, { from: number; to: number }>();\n const decorations: Decoration[] = [];\n const activeSet = new Set(activeThreadIds);\n\n doc.descendants((node, pos) => {\n for (const mark of node.marks) {\n if (mark.type !== this.type) continue;\n\n const threadId = (mark.attrs as { threadId?: string }).threadId;\n if (!threadId) continue;\n\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so we always store the largest \"to\" found.\n // AnchoredThreads component uses \"from\" as the position, so we always store the smallest \"from\" found.\n const current = threadPositions.get(threadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(threadId, {\n from: Math.min(from, current.from),\n to: Math.max(to, current.to),\n });\n\n if (activeSet.has(threadId)) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-thread-mark-selected\",\n })\n );\n }\n }\n });\n\n // Only scroll when the active selection explicitly changes.\n if (scroll && activeThreadIds.length > 0) {\n const [scrollTargetId] = activeThreadIds;\n const element = this.editor.view.dom.querySelector(\n `.lb-tiptap-thread-mark[data-lb-thread-id=\"${scrollTargetId}\"]`\n );\n element?.scrollIntoView({ behavior: \"smooth\", block: \"nearest\" });\n }\n\n return {\n decorations: DecorationSet.create(doc, decorations),\n activeThreadIds,\n threadPositions,\n };\n };\n\n // Recursively walks a Fragment and removes only this extension's comment mark from every node it finds.\n const stripCommentMarks = (slice: Slice): Slice => {\n const stripFragment = (fragment: Fragment): Fragment => {\n let changed = false;\n const nodes: Node[] = [];\n\n fragment.forEach((node) => {\n // Filter out this extension's comment mark from the node's marks so that it is not copied to the clipboard\n const nextMarks = node.marks.filter(\n (mark) => mark.type !== this.type\n );\n const marksChanged = nextMarks.length !== node.marks.length;\n\n // Recursively strip comment marks from child content (e.g. inline content inside paragraphs, list items)\n const nextContent =\n node.content.childCount > 0\n ? stripFragment(node.content)\n : node.content;\n const contentChanged = nextContent !== node.content;\n\n if (marksChanged || contentChanged) {\n changed = true;\n nodes.push(\n node.isText\n ? node.mark(nextMarks)\n : node.type.create(node.attrs, nextContent, nextMarks)\n );\n } else {\n nodes.push(node);\n }\n });\n\n return changed ? Fragment.fromArray(nodes) : fragment;\n };\n\n const content = stripFragment(slice.content);\n return content === slice.content\n ? slice\n : new Slice(content, slice.openStart, slice.openEnd);\n };\n\n return [\n new Plugin({\n key: new PluginKey(\"lb-comment-clipboard\"),\n props: {\n transformCopied: (slice) => stripCommentMarks(slice),\n transformPasted: (slice) => stripCommentMarks(slice),\n },\n }),\n new Plugin({\n key: THREADS_PLUGIN_KEY,\n state: {\n init(): ThreadPluginState {\n return {\n threadPositions: new Map(),\n activeThreadIds: [],\n decorations: DecorationSet.empty,\n };\n },\n apply(tr, state) {\n const action = tr.getMeta(THREADS_PLUGIN_KEY) as\n | ThreadPluginAction\n | undefined;\n\n if (!tr.docChanged && !action) {\n return state;\n }\n\n if (!action) {\n return updateState(tr.doc, state.activeThreadIds, {\n scroll: false,\n });\n }\n\n if (action.name === ThreadPluginActions.SET_ACTIVE_THREAD_IDS) {\n const idsChanged = !shallow(action.data, state.activeThreadIds);\n if (!tr.docChanged && !idsChanged) {\n return state;\n }\n return updateState(tr.doc, action.data, { scroll: idsChanged });\n }\n\n return state;\n },\n },\n props: {\n decorations: (state) => {\n return (\n THREADS_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n handleClick: (view, pos, event) => {\n if (event.button !== 0) return;\n\n const $pos = view.state.doc.resolve(pos);\n const ids = getVisibleThreadIdsAtPos(view.state, $pos, this.type);\n dispatchSetActiveThreadIds(view, ids);\n },\n },\n }),\n ];\n },\n});\n\nexport const CommentsExtension = Extension.create<\n { filteredThreads?: Set<string> },\n CommentsExtensionStorage\n>({\n name: \"liveblocksComments\",\n priority: 95,\n addExtensions() {\n return [Comment];\n },\n\n addStorage() {\n return {\n pendingComment: false,\n };\n },\n\n addCommands() {\n return {\n addPendingComment: () => () => {\n if (this.editor.state.selection.empty) {\n return false;\n }\n // Unselect any open threads.\n dispatchSetActiveThreadIds(this.editor.view, []);\n this.storage.pendingComment = true;\n return true;\n },\n closePendingComment: () => () => {\n this.storage.pendingComment = false;\n return true;\n },\n selectThread: (id: string | null) => () => {\n // If the target thread is filtered out, clear the active selection\n // instead of selecting an invisible thread.\n const filtered = getFilteredThreads(this.editor.state);\n const nextIds =\n id === null || (filtered && !filtered.has(id)) ? [] : [id];\n\n dispatchSetActiveThreadIds(this.editor.view, nextIds);\n return true;\n },\n addComment:\n (id: string) =>\n ({ commands }) => {\n if (\n !this.storage.pendingComment ||\n this.editor.state.selection.empty\n ) {\n return false;\n }\n commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });\n this.storage.pendingComment = false;\n return true;\n },\n };\n },\n onSelectionUpdate(\n this: { storage: CommentsExtensionStorage; editor: Editor },\n { transaction }: { transaction: Transaction }\n ) {\n const yjsMeta: unknown = transaction.getMeta(ySyncPluginKey);\n const liveblocksMeta: unknown = transaction.getMeta(\n LIVEBLOCKS_COLLABORATION_PLUGIN_KEY\n );\n const isRemoteCollaborationUpdate = yjsMeta || liveblocksMeta;\n\n // Close any pending composer when the user moves the selection locally\n // (but ignore remote collaboration-driven selection changes).\n if (this.storage.pendingComment && !isRemoteCollaborationUpdate) {\n this.storage.pendingComment = false;\n }\n\n if (this.storage.pendingComment) return;\n\n const { state } = this.editor;\n const markType = state.schema.marks[LIVEBLOCKS_COMMENT_MARK_TYPE];\n if (!markType) return;\n\n const ids = getVisibleThreadIdsAtPos(\n state,\n state.selection.$from,\n markType\n );\n const current = THREADS_PLUGIN_KEY.getState(state)?.activeThreadIds ?? [];\n if (shallow(ids, current)) return;\n\n dispatchSetActiveThreadIds(this.editor.view, ids);\n },\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: THREADS_ACTIVE_SELECTION_PLUGIN,\n props: {\n decorations: ({ doc, selection }) => {\n if (!this.storage.pendingComment) {\n return DecorationSet.create(doc, []);\n }\n const { from, to } = selection;\n const decorations: Decoration[] = [\n Decoration.inline(from, to, {\n class: \"lb-root lb-selection lb-tiptap-active-selection\",\n }),\n ];\n return DecorationSet.create(doc, decorations);\n },\n },\n }),\n new Plugin({\n key: FILTERED_THREADS_PLUGIN_KEY,\n state: {\n init: () => ({\n filteredThreads: this.options.filteredThreads,\n }),\n apply(tr, value) {\n const meta = tr.getMeta(FILTERED_THREADS_PLUGIN_KEY) as\n | { filteredThreads?: Set<string> }\n | undefined;\n if (meta?.filteredThreads) {\n return { filteredThreads: meta.filteredThreads };\n }\n return value;\n },\n },\n view: (view) => {\n const syncDom = () => {\n const filteredThreads = FILTERED_THREADS_PLUGIN_KEY.getState(\n view.state\n )?.filteredThreads;\n\n // Toggle attribute for all comment-mark spans\n const els = view.dom.querySelectorAll<HTMLElement>(\n \"span.lb-tiptap-thread-mark[data-lb-thread-id]\"\n );\n els.forEach((el) => {\n const id = el.getAttribute(\"data-lb-thread-id\");\n if (!id) return;\n if (!filteredThreads || filteredThreads.has(id)) {\n el.removeAttribute(\"data-hidden\");\n } else {\n el.setAttribute(\"data-hidden\", \"\");\n }\n });\n };\n\n queueMicrotask(syncDom);\n\n return {\n update: (view, prevState) => {\n const curr = FILTERED_THREADS_PLUGIN_KEY.getState(\n view.state\n )?.filteredThreads;\n const prev =\n FILTERED_THREADS_PLUGIN_KEY.getState(\n prevState\n )?.filteredThreads;\n\n if (\n !areSetsEqual(prev, curr) ||\n view.state.doc !== prevState.doc\n ) {\n syncDom();\n\n const active =\n THREADS_PLUGIN_KEY.getState(view.state)?.activeThreadIds ??\n [];\n\n if (active.length && curr) {\n const next = active.filter((id) => curr.has(id));\n if (next.length !== active.length) {\n dispatchSetActiveThreadIds(view, next);\n }\n }\n }\n },\n };\n },\n }),\n ];\n },\n});\n"],"names":["view"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CommentsExtension.js","sources":["../../src/comments/CommentsExtension.ts"],"sourcesContent":["import { shallow } from \"@liveblocks/core\";\nimport { type Editor, Extension, Mark, mergeAttributes } from \"@tiptap/core\";\nimport type {\n Mark as ProseMirrorMark,\n MarkType,\n Node,\n ResolvedPos,\n} from \"@tiptap/pm/model\";\nimport { Fragment, Slice } from \"@tiptap/pm/model\";\nimport type { EditorState, Transaction } from \"@tiptap/pm/state\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"../collaboration-liveblocks/plugin\";\nimport type { CommentsExtensionStorage, ThreadPluginState } from \"../types\";\nimport {\n LIVEBLOCKS_COMMENT_MARK_TYPE,\n ThreadPluginActions,\n THREADS_ACTIVE_SELECTION_PLUGIN,\n THREADS_PLUGIN_KEY,\n} from \"../types\";\nimport { areSetsEqual } from \"../utils\";\n\ntype ThreadPluginAction = {\n name: ThreadPluginActions;\n data: string[];\n};\n\nexport const FILTERED_THREADS_PLUGIN_KEY = new PluginKey<{\n filteredThreads?: Set<string>;\n}>();\n\nfunction getFilteredThreads(state: EditorState): Set<string> | undefined {\n return FILTERED_THREADS_PLUGIN_KEY.getState(state)?.filteredThreads;\n}\n\nfunction getVisibleThreadIdsFromMarks(\n marks: readonly ProseMirrorMark[],\n markType: MarkType,\n filteredThreads: Set<string> | undefined\n): string[] {\n const ids = new Set<string>();\n for (const mark of marks) {\n if (mark.type !== markType || mark.attrs.orphan) continue;\n const threadId = mark.attrs.threadId as string | undefined;\n if (!threadId) continue;\n if (filteredThreads && !filteredThreads.has(threadId)) continue;\n ids.add(threadId);\n }\n return [...ids];\n}\n\nfunction getVisibleThreadIdsAtPos(\n state: EditorState,\n $pos: ResolvedPos,\n markType: MarkType\n): string[] {\n return getVisibleThreadIdsFromMarks(\n $pos.marks(),\n markType,\n getFilteredThreads(state)\n );\n}\n\nfunction dispatchSetActiveThreadIds(view: EditorView, ids: string[]): void {\n view.dispatch(\n view.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_ACTIVE_THREAD_IDS,\n data: ids,\n } satisfies ThreadPluginAction)\n );\n}\n\nconst Comment = Mark.create({\n name: LIVEBLOCKS_COMMENT_MARK_TYPE,\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n parseHTML: () => {\n return [\n {\n tag: \"span\",\n getAttrs: (node) =>\n node.getAttribute(\"data-lb-thread-id\") !== null && null,\n },\n ];\n },\n addAttributes() {\n // Return an object with attribute configuration\n return {\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-lb-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-lb-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n const filteredThreads = this.editor\n ? FILTERED_THREADS_PLUGIN_KEY.getState(this.editor.state)?.filteredThreads\n : undefined;\n const threadId = (HTMLAttributes as { [\"data-lb-thread-id\"]: string })[\n \"data-lb-thread-id\"\n ];\n if (filteredThreads && !filteredThreads.has(threadId)) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n \"data-hidden\": \"\",\n }),\n ];\n }\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n }),\n ];\n },\n\n /**\n * This plugin tracks the (first) position of each thread mark in the doc and creates a decoration for the selected thread\n */\n addProseMirrorPlugins() {\n const updateState = (\n doc: Node,\n activeThreadIds: string[],\n { scroll }: { scroll: boolean }\n ): ThreadPluginState => {\n const threadPositions = new Map<string, { from: number; to: number }>();\n const decorations: Decoration[] = [];\n const activeSet = new Set(activeThreadIds);\n\n doc.descendants((node, pos) => {\n for (const mark of node.marks) {\n if (mark.type !== this.type) continue;\n\n const threadId = (mark.attrs as { threadId?: string }).threadId;\n if (!threadId) continue;\n\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so we always store the largest \"to\" found.\n // AnchoredThreads component uses \"from\" as the position, so we always store the smallest \"from\" found.\n const current = threadPositions.get(threadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(threadId, {\n from: Math.min(from, current.from),\n to: Math.max(to, current.to),\n });\n\n if (activeSet.has(threadId)) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-thread-mark-selected\",\n })\n );\n }\n }\n });\n\n // Only scroll when the active selection explicitly changes.\n if (scroll && activeThreadIds.length > 0) {\n const [scrollTargetId] = activeThreadIds;\n const element = this.editor.view.dom.querySelector(\n `.lb-tiptap-thread-mark[data-lb-thread-id=\"${scrollTargetId}\"]`\n );\n element?.scrollIntoView({ behavior: \"smooth\", block: \"nearest\" });\n }\n\n return {\n decorations: DecorationSet.create(doc, decorations),\n activeThreadIds,\n threadPositions,\n };\n };\n\n // Recursively walks a Fragment and removes only this extension's comment mark from every node it finds.\n const stripCommentMarks = (slice: Slice): Slice => {\n const stripFragment = (fragment: Fragment): Fragment => {\n let changed = false;\n const nodes: Node[] = [];\n\n fragment.forEach((node) => {\n // Filter out this extension's comment mark from the node's marks so that it is not copied to the clipboard\n const nextMarks = node.marks.filter(\n (mark) => mark.type !== this.type\n );\n const marksChanged = nextMarks.length !== node.marks.length;\n\n // Recursively strip comment marks from child content (e.g. inline content inside paragraphs, list items)\n const nextContent =\n node.content.childCount > 0\n ? stripFragment(node.content)\n : node.content;\n const contentChanged = nextContent !== node.content;\n\n if (marksChanged || contentChanged) {\n changed = true;\n nodes.push(\n node.isText\n ? node.mark(nextMarks)\n : node.type.create(node.attrs, nextContent, nextMarks)\n );\n } else {\n nodes.push(node);\n }\n });\n\n return changed ? Fragment.fromArray(nodes) : fragment;\n };\n\n const content = stripFragment(slice.content);\n return content === slice.content\n ? slice\n : new Slice(content, slice.openStart, slice.openEnd);\n };\n\n return [\n new Plugin({\n key: new PluginKey(\"lb-comment-clipboard\"),\n props: {\n transformCopied: (slice) => stripCommentMarks(slice),\n transformPasted: (slice) => stripCommentMarks(slice),\n },\n }),\n new Plugin({\n key: THREADS_PLUGIN_KEY,\n state: {\n init(): ThreadPluginState {\n return {\n threadPositions: new Map(),\n activeThreadIds: [],\n decorations: DecorationSet.empty,\n };\n },\n apply(tr, state) {\n const action = tr.getMeta(THREADS_PLUGIN_KEY) as\n | ThreadPluginAction\n | undefined;\n\n if (!tr.docChanged && !action) {\n return state;\n }\n\n if (!action) {\n return updateState(tr.doc, state.activeThreadIds, {\n scroll: false,\n });\n }\n\n if (action.name === ThreadPluginActions.SET_ACTIVE_THREAD_IDS) {\n const idsChanged = !shallow(action.data, state.activeThreadIds);\n if (!tr.docChanged && !idsChanged) {\n return state;\n }\n return updateState(tr.doc, action.data, { scroll: idsChanged });\n }\n\n return state;\n },\n },\n props: {\n decorations: (state) => {\n return (\n THREADS_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n handleClick: (view, pos, event) => {\n if (event.button !== 0) return;\n\n const $pos = view.state.doc.resolve(pos);\n const ids = getVisibleThreadIdsAtPos(view.state, $pos, this.type);\n dispatchSetActiveThreadIds(view, ids);\n },\n },\n }),\n ];\n },\n});\n\nexport const CommentsExtension = Extension.create<\n { filteredThreads?: Set<string> },\n CommentsExtensionStorage\n>({\n name: \"liveblocksComments\",\n priority: 95,\n addExtensions() {\n return [Comment];\n },\n\n addStorage() {\n return {\n pendingComment: false,\n };\n },\n\n addCommands() {\n return {\n addPendingComment: () => () => {\n if (this.editor.state.selection.empty) {\n return false;\n }\n // Unselect any open threads.\n dispatchSetActiveThreadIds(this.editor.view, []);\n this.storage.pendingComment = true;\n return true;\n },\n closePendingComment: () => () => {\n this.storage.pendingComment = false;\n return true;\n },\n selectThread: (id: string | null) => () => {\n // If the target thread is filtered out, clear the active selection\n // instead of selecting an invisible thread.\n const filtered = getFilteredThreads(this.editor.state);\n const nextIds =\n id === null || (filtered && !filtered.has(id)) ? [] : [id];\n\n dispatchSetActiveThreadIds(this.editor.view, nextIds);\n return true;\n },\n addComment:\n (id: string) =>\n ({ commands }) => {\n if (\n !this.storage.pendingComment ||\n this.editor.state.selection.empty\n ) {\n return false;\n }\n commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });\n this.storage.pendingComment = false;\n return true;\n },\n };\n },\n onSelectionUpdate(\n this: { storage: CommentsExtensionStorage; editor: Editor },\n { transaction }: { transaction: Transaction }\n ) {\n const yjsMeta: unknown = transaction.getMeta(ySyncPluginKey);\n const liveblocksMeta: unknown = transaction.getMeta(\n LIVEBLOCKS_COLLABORATION_PLUGIN_KEY\n );\n const isRemoteCollaborationUpdate = yjsMeta || liveblocksMeta;\n\n // Close any pending composer when the user moves the selection locally\n // (but ignore remote collaboration-driven selection changes).\n if (this.storage.pendingComment && !isRemoteCollaborationUpdate) {\n this.storage.pendingComment = false;\n }\n\n if (this.storage.pendingComment) return;\n\n const { state } = this.editor;\n const markType = state.schema.marks[LIVEBLOCKS_COMMENT_MARK_TYPE];\n if (!markType) return;\n\n const ids = getVisibleThreadIdsAtPos(\n state,\n state.selection.$from,\n markType\n );\n const current = THREADS_PLUGIN_KEY.getState(state)?.activeThreadIds ?? [];\n if (shallow(ids, current)) return;\n\n dispatchSetActiveThreadIds(this.editor.view, ids);\n },\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: THREADS_ACTIVE_SELECTION_PLUGIN,\n props: {\n decorations: ({ doc, selection }) => {\n if (!this.storage.pendingComment) {\n return DecorationSet.create(doc, []);\n }\n const { from, to } = selection;\n const decorations: Decoration[] = [\n Decoration.inline(from, to, {\n class: \"lb-root lb-selection lb-tiptap-active-selection\",\n }),\n ];\n return DecorationSet.create(doc, decorations);\n },\n },\n }),\n new Plugin({\n key: FILTERED_THREADS_PLUGIN_KEY,\n state: {\n init: () => ({\n filteredThreads: this.options.filteredThreads,\n }),\n apply(tr, value) {\n const meta = tr.getMeta(FILTERED_THREADS_PLUGIN_KEY) as\n | { filteredThreads?: Set<string> }\n | undefined;\n if (meta?.filteredThreads) {\n return { filteredThreads: meta.filteredThreads };\n }\n return value;\n },\n },\n view: (view) => {\n const syncDom = () => {\n const filteredThreads = FILTERED_THREADS_PLUGIN_KEY.getState(\n view.state\n )?.filteredThreads;\n\n // Toggle attribute for all comment-mark spans\n const els = view.dom.querySelectorAll<HTMLElement>(\n \"span.lb-tiptap-thread-mark[data-lb-thread-id]\"\n );\n els.forEach((el) => {\n const id = el.getAttribute(\"data-lb-thread-id\");\n if (!id) return;\n if (!filteredThreads || filteredThreads.has(id)) {\n el.removeAttribute(\"data-hidden\");\n } else {\n el.setAttribute(\"data-hidden\", \"\");\n }\n });\n };\n\n queueMicrotask(syncDom);\n\n return {\n update: (view, prevState) => {\n const curr = FILTERED_THREADS_PLUGIN_KEY.getState(\n view.state\n )?.filteredThreads;\n const prev =\n FILTERED_THREADS_PLUGIN_KEY.getState(\n prevState\n )?.filteredThreads;\n\n if (\n !areSetsEqual(prev, curr) ||\n view.state.doc !== prevState.doc\n ) {\n syncDom();\n\n const active =\n THREADS_PLUGIN_KEY.getState(view.state)?.activeThreadIds ??\n [];\n\n if (active.length && curr) {\n const next = active.filter((id) => curr.has(id));\n if (next.length !== active.length) {\n dispatchSetActiveThreadIds(view, next);\n }\n }\n }\n },\n };\n },\n }),\n ];\n },\n});\n"],"names":["view"],"mappings":"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"}
|
|
@@ -7,12 +7,13 @@ var state = require('@tiptap/pm/state');
|
|
|
7
7
|
var react = require('@tiptap/react');
|
|
8
8
|
var Suggestion = require('@tiptap/suggestion');
|
|
9
9
|
var yProsemirror = require('y-prosemirror');
|
|
10
|
-
|
|
10
|
+
require('../collaboration-liveblocks/plugin.cjs');
|
|
11
11
|
var types = require('../types.cjs');
|
|
12
12
|
var utils = require('../utils.cjs');
|
|
13
13
|
var GroupMentionNode = require('./GroupMentionNode.cjs');
|
|
14
14
|
var MentionNode = require('./MentionNode.cjs');
|
|
15
15
|
var MentionsList = require('./MentionsList.cjs');
|
|
16
|
+
var prosemirror = require('@liveblocks/prosemirror');
|
|
16
17
|
|
|
17
18
|
const mentionPasteHandler = () => {
|
|
18
19
|
return new state.Plugin({
|
|
@@ -46,7 +47,7 @@ const notifier = ({
|
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
if (transactions.some(
|
|
49
|
-
(transaction) => transaction.getMeta(yProsemirror.ySyncPluginKey) || transaction.getMeta(
|
|
50
|
+
(transaction) => transaction.getMeta(yProsemirror.ySyncPluginKey) || transaction.getMeta(prosemirror.LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)
|
|
50
51
|
)) {
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentionExtension.cjs","sources":["../../src/mentions/MentionExtension.ts"],"sourcesContent":["import {\n assertNever,\n createInboxNotificationId,\n MENTION_CHARACTER,\n} from \"@liveblocks/core\";\nimport {\n combineTransactionSteps,\n type Content,\n Extension,\n getChangedRanges,\n} from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { ReactRenderer } from \"@tiptap/react\";\nimport Suggestion from \"@tiptap/suggestion\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"../collaboration-liveblocks/plugin\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_EXTENSION,\n LIVEBLOCKS_MENTION_KEY,\n LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n LIVEBLOCKS_MENTION_PASTE_KEY,\n LIVEBLOCKS_MENTION_TYPE,\n type TiptapMentionData,\n} from \"../types\";\nimport { getMentionsFromNode, mapFragment } from \"../utils\";\nimport { GroupMentionNode } from \"./GroupMentionNode\";\nimport { MentionNode } from \"./MentionNode\";\nimport type { MentionsListHandle, MentionsListProps } from \"./MentionsList\";\nimport { MentionsList } from \"./MentionsList\";\n\n/**\n *\n * Handles creating new notificationIds when notifications are pasted\n *\n * @returns Plugin\n */\nconst mentionPasteHandler = (): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_PASTE_KEY,\n props: {\n transformPasted: (slice) => {\n const getNewNotificationIds = (node: ProseMirrorNode) => {\n // If this is a mention node, we need to get a new notification id\n if (\n node.type.name === LIVEBLOCKS_MENTION_TYPE ||\n node.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n return node.type.create(\n { ...node.attrs, notificationId: createInboxNotificationId() },\n node.content\n );\n }\n return node.copy(node.content);\n };\n const fragment = mapFragment(slice.content, getNewNotificationIds);\n return new Slice(fragment, slice.openStart, slice.openEnd);\n },\n },\n });\n};\n\nexport type MentionExtensionOptions = {\n onCreateMention: (mention: TiptapMentionData) => void;\n onDeleteMention: (notificationId: string) => void;\n};\n/**\n *\n * The purpose of this plugin is to create inbox notifications when a mention is\n *\n * @returns Plugin (from @tiptap/core)\n */\nconst notifier = ({\n onCreateMention,\n onDeleteMention,\n}: MentionExtensionOptions): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n appendTransaction: (transactions, oldState, newState) => {\n const docChanges =\n transactions.some((transaction) => transaction.docChanged) &&\n !oldState.doc.eq(newState.doc);\n // don't run if there was no change\n if (!docChanges) {\n return;\n }\n // don't run if from collab\n if (\n transactions.some(\n (transaction) =>\n transaction.getMeta(ySyncPluginKey) ||\n transaction.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)\n )\n ) {\n return;\n }\n const transform = combineTransactionSteps(oldState.doc, [\n ...transactions,\n ]);\n const changes = getChangedRanges(transform);\n\n changes.forEach(({ newRange, oldRange }) => {\n const newMentions = getMentionsFromNode(newState.doc, newRange);\n const oldMentions = getMentionsFromNode(oldState.doc, oldRange);\n\n if (oldMentions.size || newMentions.size) {\n // create new mentions\n newMentions.forEach((mention) => {\n if (!oldMentions.has(mention.notificationId)) {\n onCreateMention(mention);\n }\n });\n // delete old mentions\n oldMentions.forEach((mention) => {\n if (!newMentions.has(mention.notificationId)) {\n onDeleteMention(mention.notificationId);\n }\n });\n }\n });\n\n return undefined;\n },\n });\n};\n\nexport const MentionExtension = Extension.create<MentionExtensionOptions>({\n name: LIVEBLOCKS_MENTION_EXTENSION,\n\n priority: 101,\n addOptions() {\n return {\n onCreateMention: () => {},\n onDeleteMention: () => {},\n };\n },\n\n addExtensions() {\n return [MentionNode, GroupMentionNode];\n },\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n editor: this.editor,\n char: MENTION_CHARACTER,\n pluginKey: LIVEBLOCKS_MENTION_KEY,\n command: ({ editor, range, props }) => {\n // increase range.to by one when the next node is of type \"text\"\n // and starts with a space character\n const nodeAfter = editor.view.state.selection.$to.nodeAfter;\n const overrideSpace = nodeAfter?.text?.startsWith(\" \");\n\n if (overrideSpace) {\n range.to += 1;\n }\n\n const mention = props as TiptapMentionData;\n\n let mentionNode: Content;\n\n if (mention.kind === \"user\") {\n mentionNode = {\n type: LIVEBLOCKS_MENTION_TYPE,\n attrs: {\n id: mention.id,\n notificationId: mention.notificationId,\n },\n };\n } else if (mention.kind === \"group\") {\n mentionNode = {\n type: LIVEBLOCKS_GROUP_MENTION_TYPE,\n attrs: {\n id: mention.id,\n userIds: mention.userIds\n ? JSON.stringify(mention.userIds)\n : undefined,\n notificationId: mention.notificationId,\n },\n };\n } else {\n assertNever(mention, \"Unhandled mention kind\");\n }\n\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n mentionNode,\n {\n type: \"text\",\n text: \" \",\n },\n ])\n .run();\n\n // get reference to `window` object from editor element, to support cross-frame JS usage\n editor.view.dom.ownerDocument.defaultView\n ?.getSelection()\n ?.collapseToEnd();\n },\n allow: ({ state, range }) => {\n const $fromParentType = state.doc.resolve(range.from).parent.type;\n\n return Boolean(\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_MENTION_TYPE]\n ) ||\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_GROUP_MENTION_TYPE]\n )\n );\n },\n allowSpaces: true,\n items: () => [], // we'll let the mentions list component do this\n render: () => {\n let component: ReactRenderer<MentionsListHandle, MentionsListProps>;\n return {\n onStart: (props) => {\n component = new ReactRenderer<\n MentionsListHandle,\n MentionsListProps\n >(MentionsList, {\n props,\n editor: props.editor,\n });\n\n if (!props.clientRect) {\n return;\n }\n\n document.body.appendChild(component.element);\n },\n\n onUpdate(props) {\n component.updateProps(props);\n },\n\n onKeyDown(props) {\n if (props.event.key === \"Escape\") {\n component.updateProps({\n ...props,\n hide: true,\n });\n return true;\n }\n return component.ref?.onKeyDown(props) ?? false;\n },\n\n onExit() {\n if (document.body.contains(component.element)) {\n document.body.removeChild(component.element);\n }\n component.destroy();\n },\n };\n },\n }),\n notifier(this.options),\n mentionPasteHandler(),\n ];\n },\n});\n"],"names":["Plugin","LIVEBLOCKS_MENTION_PASTE_KEY","LIVEBLOCKS_MENTION_TYPE","LIVEBLOCKS_GROUP_MENTION_TYPE","createInboxNotificationId","mapFragment","Slice","LIVEBLOCKS_MENTION_NOTIFIER_KEY","ySyncPluginKey","LIVEBLOCKS_COLLABORATION_PLUGIN_KEY","combineTransactionSteps","getChangedRanges","getMentionsFromNode","Extension","LIVEBLOCKS_MENTION_EXTENSION","MentionNode","GroupMentionNode","MENTION_CHARACTER","LIVEBLOCKS_MENTION_KEY","assertNever","ReactRenderer","MentionsList"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MentionExtension.cjs","sources":["../../src/mentions/MentionExtension.ts"],"sourcesContent":["import {\n assertNever,\n createInboxNotificationId,\n MENTION_CHARACTER,\n} from \"@liveblocks/core\";\nimport {\n combineTransactionSteps,\n type Content,\n Extension,\n getChangedRanges,\n} from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { ReactRenderer } from \"@tiptap/react\";\nimport Suggestion from \"@tiptap/suggestion\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"../collaboration-liveblocks/plugin\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_EXTENSION,\n LIVEBLOCKS_MENTION_KEY,\n LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n LIVEBLOCKS_MENTION_PASTE_KEY,\n LIVEBLOCKS_MENTION_TYPE,\n type TiptapMentionData,\n} from \"../types\";\nimport { getMentionsFromNode, mapFragment } from \"../utils\";\nimport { GroupMentionNode } from \"./GroupMentionNode\";\nimport { MentionNode } from \"./MentionNode\";\nimport type { MentionsListHandle, MentionsListProps } from \"./MentionsList\";\nimport { MentionsList } from \"./MentionsList\";\n\n/**\n *\n * Handles creating new notificationIds when notifications are pasted\n *\n * @returns Plugin\n */\nconst mentionPasteHandler = (): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_PASTE_KEY,\n props: {\n transformPasted: (slice) => {\n const getNewNotificationIds = (node: ProseMirrorNode) => {\n // If this is a mention node, we need to get a new notification id\n if (\n node.type.name === LIVEBLOCKS_MENTION_TYPE ||\n node.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n return node.type.create(\n { ...node.attrs, notificationId: createInboxNotificationId() },\n node.content\n );\n }\n return node.copy(node.content);\n };\n const fragment = mapFragment(slice.content, getNewNotificationIds);\n return new Slice(fragment, slice.openStart, slice.openEnd);\n },\n },\n });\n};\n\nexport type MentionExtensionOptions = {\n onCreateMention: (mention: TiptapMentionData) => void;\n onDeleteMention: (notificationId: string) => void;\n};\n/**\n *\n * The purpose of this plugin is to create inbox notifications when a mention is\n *\n * @returns Plugin (from @tiptap/core)\n */\nconst notifier = ({\n onCreateMention,\n onDeleteMention,\n}: MentionExtensionOptions): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n appendTransaction: (transactions, oldState, newState) => {\n const docChanges =\n transactions.some((transaction) => transaction.docChanged) &&\n !oldState.doc.eq(newState.doc);\n // don't run if there was no change\n if (!docChanges) {\n return;\n }\n // don't run if from collab\n if (\n transactions.some(\n (transaction) =>\n transaction.getMeta(ySyncPluginKey) ||\n transaction.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)\n )\n ) {\n return;\n }\n const transform = combineTransactionSteps(oldState.doc, [\n ...transactions,\n ]);\n const changes = getChangedRanges(transform);\n\n changes.forEach(({ newRange, oldRange }) => {\n const newMentions = getMentionsFromNode(newState.doc, newRange);\n const oldMentions = getMentionsFromNode(oldState.doc, oldRange);\n\n if (oldMentions.size || newMentions.size) {\n // create new mentions\n newMentions.forEach((mention) => {\n if (!oldMentions.has(mention.notificationId)) {\n onCreateMention(mention);\n }\n });\n // delete old mentions\n oldMentions.forEach((mention) => {\n if (!newMentions.has(mention.notificationId)) {\n onDeleteMention(mention.notificationId);\n }\n });\n }\n });\n\n return undefined;\n },\n });\n};\n\nexport const MentionExtension = Extension.create<MentionExtensionOptions>({\n name: LIVEBLOCKS_MENTION_EXTENSION,\n\n priority: 101,\n addOptions() {\n return {\n onCreateMention: () => {},\n onDeleteMention: () => {},\n };\n },\n\n addExtensions() {\n return [MentionNode, GroupMentionNode];\n },\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n editor: this.editor,\n char: MENTION_CHARACTER,\n pluginKey: LIVEBLOCKS_MENTION_KEY,\n command: ({ editor, range, props }) => {\n // increase range.to by one when the next node is of type \"text\"\n // and starts with a space character\n const nodeAfter = editor.view.state.selection.$to.nodeAfter;\n const overrideSpace = nodeAfter?.text?.startsWith(\" \");\n\n if (overrideSpace) {\n range.to += 1;\n }\n\n const mention = props as TiptapMentionData;\n\n let mentionNode: Content;\n\n if (mention.kind === \"user\") {\n mentionNode = {\n type: LIVEBLOCKS_MENTION_TYPE,\n attrs: {\n id: mention.id,\n notificationId: mention.notificationId,\n },\n };\n } else if (mention.kind === \"group\") {\n mentionNode = {\n type: LIVEBLOCKS_GROUP_MENTION_TYPE,\n attrs: {\n id: mention.id,\n userIds: mention.userIds\n ? JSON.stringify(mention.userIds)\n : undefined,\n notificationId: mention.notificationId,\n },\n };\n } else {\n assertNever(mention, \"Unhandled mention kind\");\n }\n\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n mentionNode,\n {\n type: \"text\",\n text: \" \",\n },\n ])\n .run();\n\n // get reference to `window` object from editor element, to support cross-frame JS usage\n editor.view.dom.ownerDocument.defaultView\n ?.getSelection()\n ?.collapseToEnd();\n },\n allow: ({ state, range }) => {\n const $fromParentType = state.doc.resolve(range.from).parent.type;\n\n return Boolean(\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_MENTION_TYPE]\n ) ||\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_GROUP_MENTION_TYPE]\n )\n );\n },\n allowSpaces: true,\n items: () => [], // we'll let the mentions list component do this\n render: () => {\n let component: ReactRenderer<MentionsListHandle, MentionsListProps>;\n return {\n onStart: (props) => {\n component = new ReactRenderer<\n MentionsListHandle,\n MentionsListProps\n >(MentionsList, {\n props,\n editor: props.editor,\n });\n\n if (!props.clientRect) {\n return;\n }\n\n document.body.appendChild(component.element);\n },\n\n onUpdate(props) {\n component.updateProps(props);\n },\n\n onKeyDown(props) {\n if (props.event.key === \"Escape\") {\n component.updateProps({\n ...props,\n hide: true,\n });\n return true;\n }\n return component.ref?.onKeyDown(props) ?? false;\n },\n\n onExit() {\n if (document.body.contains(component.element)) {\n document.body.removeChild(component.element);\n }\n component.destroy();\n },\n };\n },\n }),\n notifier(this.options),\n mentionPasteHandler(),\n ];\n },\n});\n"],"names":["Plugin","LIVEBLOCKS_MENTION_PASTE_KEY","LIVEBLOCKS_MENTION_TYPE","LIVEBLOCKS_GROUP_MENTION_TYPE","createInboxNotificationId","mapFragment","Slice","LIVEBLOCKS_MENTION_NOTIFIER_KEY","ySyncPluginKey","LIVEBLOCKS_COLLABORATION_PLUGIN_KEY","combineTransactionSteps","getChangedRanges","getMentionsFromNode","Extension","LIVEBLOCKS_MENTION_EXTENSION","MentionNode","GroupMentionNode","MENTION_CHARACTER","LIVEBLOCKS_MENTION_KEY","assertNever","ReactRenderer","MentionsList"],"mappings":";;;;;;;;;;;;;;;;;AAwCA,MAAM,sBAAsB,MAAc;AACxC,EAAA,OAAO,IAAIA,YAAO,CAAA;AAAA,IAChB,GAAK,EAAAC,kCAAA;AAAA,IACL,KAAO,EAAA;AAAA,MACL,eAAA,EAAiB,CAAC,KAAU,KAAA;AAC1B,QAAM,MAAA,qBAAA,GAAwB,CAAC,IAA0B,KAAA;AAEvD,UAAA,IACE,KAAK,IAAK,CAAA,IAAA,KAASC,iCACnB,IAAK,CAAA,IAAA,CAAK,SAASC,mCACnB,EAAA;AACA,YAAA,OAAO,KAAK,IAAK,CAAA,MAAA;AAAA,cACf,EAAE,GAAG,IAAA,CAAK,KAAO,EAAA,cAAA,EAAgBC,gCAA4B,EAAA;AAAA,cAC7D,IAAK,CAAA,OAAA;AAAA,aACP,CAAA;AAAA,WACF;AACA,UAAO,OAAA,IAAA,CAAK,IAAK,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,SAC/B,CAAA;AACA,QAAA,MAAM,QAAW,GAAAC,iBAAA,CAAY,KAAM,CAAA,OAAA,EAAS,qBAAqB,CAAA,CAAA;AACjE,QAAA,OAAO,IAAIC,WAAM,CAAA,QAAA,EAAU,KAAM,CAAA,SAAA,EAAW,MAAM,OAAO,CAAA,CAAA;AAAA,OAC3D;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH,CAAA,CAAA;AAYA,MAAM,WAAW,CAAC;AAAA,EAChB,eAAA;AAAA,EACA,eAAA;AACF,CAAuC,KAAA;AACrC,EAAA,OAAO,IAAIN,YAAO,CAAA;AAAA,IAChB,GAAK,EAAAO,qCAAA;AAAA,IACL,iBAAmB,EAAA,CAAC,YAAc,EAAA,QAAA,EAAU,QAAa,KAAA;AACvD,MAAA,MAAM,UACJ,GAAA,YAAA,CAAa,IAAK,CAAA,CAAC,WAAgB,KAAA,WAAA,CAAY,UAAU,CAAA,IACzD,CAAC,QAAA,CAAS,GAAI,CAAA,EAAA,CAAG,SAAS,GAAG,CAAA,CAAA;AAE/B,MAAA,IAAI,CAAC,UAAY,EAAA;AACf,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,IACE,YAAa,CAAA,IAAA;AAAA,QACX,CAAC,gBACC,WAAY,CAAA,OAAA,CAAQC,2BAAc,CAClC,IAAA,WAAA,CAAY,QAAQC,+CAAmC,CAAA;AAAA,OAE3D,EAAA;AACA,QAAA,OAAA;AAAA,OACF;AACA,MAAM,MAAA,SAAA,GAAYC,8BAAwB,CAAA,QAAA,CAAS,GAAK,EAAA;AAAA,QACtD,GAAG,YAAA;AAAA,OACJ,CAAA,CAAA;AACD,MAAM,MAAA,OAAA,GAAUC,wBAAiB,SAAS,CAAA,CAAA;AAE1C,MAAA,OAAA,CAAQ,OAAQ,CAAA,CAAC,EAAE,QAAA,EAAU,UAAe,KAAA;AAC1C,QAAA,MAAM,WAAc,GAAAC,yBAAA,CAAoB,QAAS,CAAA,GAAA,EAAK,QAAQ,CAAA,CAAA;AAC9D,QAAA,MAAM,WAAc,GAAAA,yBAAA,CAAoB,QAAS,CAAA,GAAA,EAAK,QAAQ,CAAA,CAAA;AAE9D,QAAI,IAAA,WAAA,CAAY,IAAQ,IAAA,WAAA,CAAY,IAAM,EAAA;AAExC,UAAY,WAAA,CAAA,OAAA,CAAQ,CAAC,OAAY,KAAA;AAC/B,YAAA,IAAI,CAAC,WAAA,CAAY,GAAI,CAAA,OAAA,CAAQ,cAAc,CAAG,EAAA;AAC5C,cAAA,eAAA,CAAgB,OAAO,CAAA,CAAA;AAAA,aACzB;AAAA,WACD,CAAA,CAAA;AAED,UAAY,WAAA,CAAA,OAAA,CAAQ,CAAC,OAAY,KAAA;AAC/B,YAAA,IAAI,CAAC,WAAA,CAAY,GAAI,CAAA,OAAA,CAAQ,cAAc,CAAG,EAAA;AAC5C,cAAA,eAAA,CAAgB,QAAQ,cAAc,CAAA,CAAA;AAAA,aACxC;AAAA,WACD,CAAA,CAAA;AAAA,SACH;AAAA,OACD,CAAA,CAAA;AAED,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACT;AAAA,GACD,CAAA,CAAA;AACH,CAAA,CAAA;AAEa,MAAA,gBAAA,GAAmBC,iBAAU,MAAgC,CAAA;AAAA,EACxE,IAAM,EAAAC,kCAAA;AAAA,EAEN,QAAU,EAAA,GAAA;AAAA,EACV,UAAa,GAAA;AACX,IAAO,OAAA;AAAA,MACL,iBAAiB,MAAM;AAAA,OAAC;AAAA,MACxB,iBAAiB,MAAM;AAAA,OAAC;AAAA,KAC1B,CAAA;AAAA,GACF;AAAA,EAEA,aAAgB,GAAA;AACd,IAAO,OAAA,CAACC,yBAAaC,iCAAgB,CAAA,CAAA;AAAA,GACvC;AAAA,EAEA,qBAAwB,GAAA;AACtB,IAAO,OAAA;AAAA,MACL,UAAW,CAAA;AAAA,QACT,QAAQ,IAAK,CAAA,MAAA;AAAA,QACb,IAAM,EAAAC,sBAAA;AAAA,QACN,SAAW,EAAAC,4BAAA;AAAA,QACX,SAAS,CAAC,EAAE,MAAQ,EAAA,KAAA,EAAO,OAAY,KAAA;AAGrC,UAAA,MAAM,SAAY,GAAA,MAAA,CAAO,IAAK,CAAA,KAAA,CAAM,UAAU,GAAI,CAAA,SAAA,CAAA;AAClD,UAAA,MAAM,aAAgB,GAAA,SAAA,EAAW,IAAM,EAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAErD,UAAA,IAAI,aAAe,EAAA;AACjB,YAAA,KAAA,CAAM,EAAM,IAAA,CAAA,CAAA;AAAA,WACd;AAEA,UAAA,MAAM,OAAU,GAAA,KAAA,CAAA;AAEhB,UAAI,IAAA,WAAA,CAAA;AAEJ,UAAI,IAAA,OAAA,CAAQ,SAAS,MAAQ,EAAA;AAC3B,YAAc,WAAA,GAAA;AAAA,cACZ,IAAM,EAAAhB,6BAAA;AAAA,cACN,KAAO,EAAA;AAAA,gBACL,IAAI,OAAQ,CAAA,EAAA;AAAA,gBACZ,gBAAgB,OAAQ,CAAA,cAAA;AAAA,eAC1B;AAAA,aACF,CAAA;AAAA,WACF,MAAA,IAAW,OAAQ,CAAA,IAAA,KAAS,OAAS,EAAA;AACnC,YAAc,WAAA,GAAA;AAAA,cACZ,IAAM,EAAAC,mCAAA;AAAA,cACN,KAAO,EAAA;AAAA,gBACL,IAAI,OAAQ,CAAA,EAAA;AAAA,gBACZ,SAAS,OAAQ,CAAA,OAAA,GACb,KAAK,SAAU,CAAA,OAAA,CAAQ,OAAO,CAC9B,GAAA,KAAA,CAAA;AAAA,gBACJ,gBAAgB,OAAQ,CAAA,cAAA;AAAA,eAC1B;AAAA,aACF,CAAA;AAAA,WACK,MAAA;AACL,YAAAgB,gBAAA,CAAY,SAAS,wBAAwB,CAAA,CAAA;AAAA,WAC/C;AAEA,UAAA,MAAA,CACG,KAAM,EAAA,CACN,KAAM,EAAA,CACN,gBAAgB,KAAO,EAAA;AAAA,YACtB,WAAA;AAAA,YACA;AAAA,cACE,IAAM,EAAA,MAAA;AAAA,cACN,IAAM,EAAA,GAAA;AAAA,aACR;AAAA,WACD,EACA,GAAI,EAAA,CAAA;AAGP,UAAA,MAAA,CAAO,KAAK,GAAI,CAAA,aAAA,CAAc,WAC1B,EAAA,YAAA,IACA,aAAc,EAAA,CAAA;AAAA,SACpB;AAAA,QACA,KAAO,EAAA,CAAC,EAAE,KAAA,EAAO,OAAY,KAAA;AAC3B,UAAA,MAAM,kBAAkB,KAAM,CAAA,GAAA,CAAI,QAAQ,KAAM,CAAA,IAAI,EAAE,MAAO,CAAA,IAAA,CAAA;AAE7D,UAAO,OAAA,OAAA;AAAA,YACL,gBAAgB,YAAa,CAAA,SAAA;AAAA,cAC3B,KAAA,CAAM,MAAO,CAAA,KAAA,CAAMjB,6BAAuB,CAAA;AAAA,aAC5C,IACA,gBAAgB,YAAa,CAAA,SAAA;AAAA,cAC3B,KAAA,CAAM,MAAO,CAAA,KAAA,CAAMC,mCAA6B,CAAA;AAAA,aAClD;AAAA,WACF,CAAA;AAAA,SACF;AAAA,QACA,WAAa,EAAA,IAAA;AAAA,QACb,KAAA,EAAO,MAAM,EAAC;AAAA;AAAA,QACd,QAAQ,MAAM;AACZ,UAAI,IAAA,SAAA,CAAA;AACJ,UAAO,OAAA;AAAA,YACL,OAAA,EAAS,CAAC,KAAU,KAAA;AAClB,cAAY,SAAA,GAAA,IAAIiB,oBAGdC,yBAAc,EAAA;AAAA,gBACd,KAAA;AAAA,gBACA,QAAQ,KAAM,CAAA,MAAA;AAAA,eACf,CAAA,CAAA;AAED,cAAI,IAAA,CAAC,MAAM,UAAY,EAAA;AACrB,gBAAA,OAAA;AAAA,eACF;AAEA,cAAS,QAAA,CAAA,IAAA,CAAK,WAAY,CAAA,SAAA,CAAU,OAAO,CAAA,CAAA;AAAA,aAC7C;AAAA,YAEA,SAAS,KAAO,EAAA;AACd,cAAA,SAAA,CAAU,YAAY,KAAK,CAAA,CAAA;AAAA,aAC7B;AAAA,YAEA,UAAU,KAAO,EAAA;AACf,cAAI,IAAA,KAAA,CAAM,KAAM,CAAA,GAAA,KAAQ,QAAU,EAAA;AAChC,gBAAA,SAAA,CAAU,WAAY,CAAA;AAAA,kBACpB,GAAG,KAAA;AAAA,kBACH,IAAM,EAAA,IAAA;AAAA,iBACP,CAAA,CAAA;AACD,gBAAO,OAAA,IAAA,CAAA;AAAA,eACT;AACA,cAAA,OAAO,SAAU,CAAA,GAAA,EAAK,SAAU,CAAA,KAAK,CAAK,IAAA,KAAA,CAAA;AAAA,aAC5C;AAAA,YAEA,MAAS,GAAA;AACP,cAAA,IAAI,QAAS,CAAA,IAAA,CAAK,QAAS,CAAA,SAAA,CAAU,OAAO,CAAG,EAAA;AAC7C,gBAAS,QAAA,CAAA,IAAA,CAAK,WAAY,CAAA,SAAA,CAAU,OAAO,CAAA,CAAA;AAAA,eAC7C;AACA,cAAA,SAAA,CAAU,OAAQ,EAAA,CAAA;AAAA,aACpB;AAAA,WACF,CAAA;AAAA,SACF;AAAA,OACD,CAAA;AAAA,MACD,QAAA,CAAS,KAAK,OAAO,CAAA;AAAA,MACrB,mBAAoB,EAAA;AAAA,KACtB,CAAA;AAAA,GACF;AACF,CAAC;;;;"}
|
|
@@ -5,12 +5,13 @@ import { Plugin } from '@tiptap/pm/state';
|
|
|
5
5
|
import { ReactRenderer } from '@tiptap/react';
|
|
6
6
|
import Suggestion from '@tiptap/suggestion';
|
|
7
7
|
import { ySyncPluginKey } from 'y-prosemirror';
|
|
8
|
-
import
|
|
8
|
+
import '../collaboration-liveblocks/plugin.js';
|
|
9
9
|
import { LIVEBLOCKS_MENTION_PASTE_KEY, LIVEBLOCKS_MENTION_TYPE, LIVEBLOCKS_GROUP_MENTION_TYPE, LIVEBLOCKS_MENTION_NOTIFIER_KEY, LIVEBLOCKS_MENTION_EXTENSION, LIVEBLOCKS_MENTION_KEY } from '../types.js';
|
|
10
10
|
import { mapFragment, getMentionsFromNode } from '../utils.js';
|
|
11
11
|
import { GroupMentionNode } from './GroupMentionNode.js';
|
|
12
12
|
import { MentionNode } from './MentionNode.js';
|
|
13
13
|
import { MentionsList } from './MentionsList.js';
|
|
14
|
+
import { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from '@liveblocks/prosemirror';
|
|
14
15
|
|
|
15
16
|
const mentionPasteHandler = () => {
|
|
16
17
|
return new Plugin({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentionExtension.js","sources":["../../src/mentions/MentionExtension.ts"],"sourcesContent":["import {\n assertNever,\n createInboxNotificationId,\n MENTION_CHARACTER,\n} from \"@liveblocks/core\";\nimport {\n combineTransactionSteps,\n type Content,\n Extension,\n getChangedRanges,\n} from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { ReactRenderer } from \"@tiptap/react\";\nimport Suggestion from \"@tiptap/suggestion\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"../collaboration-liveblocks/plugin\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_EXTENSION,\n LIVEBLOCKS_MENTION_KEY,\n LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n LIVEBLOCKS_MENTION_PASTE_KEY,\n LIVEBLOCKS_MENTION_TYPE,\n type TiptapMentionData,\n} from \"../types\";\nimport { getMentionsFromNode, mapFragment } from \"../utils\";\nimport { GroupMentionNode } from \"./GroupMentionNode\";\nimport { MentionNode } from \"./MentionNode\";\nimport type { MentionsListHandle, MentionsListProps } from \"./MentionsList\";\nimport { MentionsList } from \"./MentionsList\";\n\n/**\n *\n * Handles creating new notificationIds when notifications are pasted\n *\n * @returns Plugin\n */\nconst mentionPasteHandler = (): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_PASTE_KEY,\n props: {\n transformPasted: (slice) => {\n const getNewNotificationIds = (node: ProseMirrorNode) => {\n // If this is a mention node, we need to get a new notification id\n if (\n node.type.name === LIVEBLOCKS_MENTION_TYPE ||\n node.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n return node.type.create(\n { ...node.attrs, notificationId: createInboxNotificationId() },\n node.content\n );\n }\n return node.copy(node.content);\n };\n const fragment = mapFragment(slice.content, getNewNotificationIds);\n return new Slice(fragment, slice.openStart, slice.openEnd);\n },\n },\n });\n};\n\nexport type MentionExtensionOptions = {\n onCreateMention: (mention: TiptapMentionData) => void;\n onDeleteMention: (notificationId: string) => void;\n};\n/**\n *\n * The purpose of this plugin is to create inbox notifications when a mention is\n *\n * @returns Plugin (from @tiptap/core)\n */\nconst notifier = ({\n onCreateMention,\n onDeleteMention,\n}: MentionExtensionOptions): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n appendTransaction: (transactions, oldState, newState) => {\n const docChanges =\n transactions.some((transaction) => transaction.docChanged) &&\n !oldState.doc.eq(newState.doc);\n // don't run if there was no change\n if (!docChanges) {\n return;\n }\n // don't run if from collab\n if (\n transactions.some(\n (transaction) =>\n transaction.getMeta(ySyncPluginKey) ||\n transaction.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)\n )\n ) {\n return;\n }\n const transform = combineTransactionSteps(oldState.doc, [\n ...transactions,\n ]);\n const changes = getChangedRanges(transform);\n\n changes.forEach(({ newRange, oldRange }) => {\n const newMentions = getMentionsFromNode(newState.doc, newRange);\n const oldMentions = getMentionsFromNode(oldState.doc, oldRange);\n\n if (oldMentions.size || newMentions.size) {\n // create new mentions\n newMentions.forEach((mention) => {\n if (!oldMentions.has(mention.notificationId)) {\n onCreateMention(mention);\n }\n });\n // delete old mentions\n oldMentions.forEach((mention) => {\n if (!newMentions.has(mention.notificationId)) {\n onDeleteMention(mention.notificationId);\n }\n });\n }\n });\n\n return undefined;\n },\n });\n};\n\nexport const MentionExtension = Extension.create<MentionExtensionOptions>({\n name: LIVEBLOCKS_MENTION_EXTENSION,\n\n priority: 101,\n addOptions() {\n return {\n onCreateMention: () => {},\n onDeleteMention: () => {},\n };\n },\n\n addExtensions() {\n return [MentionNode, GroupMentionNode];\n },\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n editor: this.editor,\n char: MENTION_CHARACTER,\n pluginKey: LIVEBLOCKS_MENTION_KEY,\n command: ({ editor, range, props }) => {\n // increase range.to by one when the next node is of type \"text\"\n // and starts with a space character\n const nodeAfter = editor.view.state.selection.$to.nodeAfter;\n const overrideSpace = nodeAfter?.text?.startsWith(\" \");\n\n if (overrideSpace) {\n range.to += 1;\n }\n\n const mention = props as TiptapMentionData;\n\n let mentionNode: Content;\n\n if (mention.kind === \"user\") {\n mentionNode = {\n type: LIVEBLOCKS_MENTION_TYPE,\n attrs: {\n id: mention.id,\n notificationId: mention.notificationId,\n },\n };\n } else if (mention.kind === \"group\") {\n mentionNode = {\n type: LIVEBLOCKS_GROUP_MENTION_TYPE,\n attrs: {\n id: mention.id,\n userIds: mention.userIds\n ? JSON.stringify(mention.userIds)\n : undefined,\n notificationId: mention.notificationId,\n },\n };\n } else {\n assertNever(mention, \"Unhandled mention kind\");\n }\n\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n mentionNode,\n {\n type: \"text\",\n text: \" \",\n },\n ])\n .run();\n\n // get reference to `window` object from editor element, to support cross-frame JS usage\n editor.view.dom.ownerDocument.defaultView\n ?.getSelection()\n ?.collapseToEnd();\n },\n allow: ({ state, range }) => {\n const $fromParentType = state.doc.resolve(range.from).parent.type;\n\n return Boolean(\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_MENTION_TYPE]\n ) ||\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_GROUP_MENTION_TYPE]\n )\n );\n },\n allowSpaces: true,\n items: () => [], // we'll let the mentions list component do this\n render: () => {\n let component: ReactRenderer<MentionsListHandle, MentionsListProps>;\n return {\n onStart: (props) => {\n component = new ReactRenderer<\n MentionsListHandle,\n MentionsListProps\n >(MentionsList, {\n props,\n editor: props.editor,\n });\n\n if (!props.clientRect) {\n return;\n }\n\n document.body.appendChild(component.element);\n },\n\n onUpdate(props) {\n component.updateProps(props);\n },\n\n onKeyDown(props) {\n if (props.event.key === \"Escape\") {\n component.updateProps({\n ...props,\n hide: true,\n });\n return true;\n }\n return component.ref?.onKeyDown(props) ?? false;\n },\n\n onExit() {\n if (document.body.contains(component.element)) {\n document.body.removeChild(component.element);\n }\n component.destroy();\n },\n };\n },\n }),\n notifier(this.options),\n mentionPasteHandler(),\n ];\n },\n});\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MentionExtension.js","sources":["../../src/mentions/MentionExtension.ts"],"sourcesContent":["import {\n assertNever,\n createInboxNotificationId,\n MENTION_CHARACTER,\n} from \"@liveblocks/core\";\nimport {\n combineTransactionSteps,\n type Content,\n Extension,\n getChangedRanges,\n} from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { ReactRenderer } from \"@tiptap/react\";\nimport Suggestion from \"@tiptap/suggestion\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"../collaboration-liveblocks/plugin\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_EXTENSION,\n LIVEBLOCKS_MENTION_KEY,\n LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n LIVEBLOCKS_MENTION_PASTE_KEY,\n LIVEBLOCKS_MENTION_TYPE,\n type TiptapMentionData,\n} from \"../types\";\nimport { getMentionsFromNode, mapFragment } from \"../utils\";\nimport { GroupMentionNode } from \"./GroupMentionNode\";\nimport { MentionNode } from \"./MentionNode\";\nimport type { MentionsListHandle, MentionsListProps } from \"./MentionsList\";\nimport { MentionsList } from \"./MentionsList\";\n\n/**\n *\n * Handles creating new notificationIds when notifications are pasted\n *\n * @returns Plugin\n */\nconst mentionPasteHandler = (): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_PASTE_KEY,\n props: {\n transformPasted: (slice) => {\n const getNewNotificationIds = (node: ProseMirrorNode) => {\n // If this is a mention node, we need to get a new notification id\n if (\n node.type.name === LIVEBLOCKS_MENTION_TYPE ||\n node.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n return node.type.create(\n { ...node.attrs, notificationId: createInboxNotificationId() },\n node.content\n );\n }\n return node.copy(node.content);\n };\n const fragment = mapFragment(slice.content, getNewNotificationIds);\n return new Slice(fragment, slice.openStart, slice.openEnd);\n },\n },\n });\n};\n\nexport type MentionExtensionOptions = {\n onCreateMention: (mention: TiptapMentionData) => void;\n onDeleteMention: (notificationId: string) => void;\n};\n/**\n *\n * The purpose of this plugin is to create inbox notifications when a mention is\n *\n * @returns Plugin (from @tiptap/core)\n */\nconst notifier = ({\n onCreateMention,\n onDeleteMention,\n}: MentionExtensionOptions): Plugin => {\n return new Plugin({\n key: LIVEBLOCKS_MENTION_NOTIFIER_KEY,\n appendTransaction: (transactions, oldState, newState) => {\n const docChanges =\n transactions.some((transaction) => transaction.docChanged) &&\n !oldState.doc.eq(newState.doc);\n // don't run if there was no change\n if (!docChanges) {\n return;\n }\n // don't run if from collab\n if (\n transactions.some(\n (transaction) =>\n transaction.getMeta(ySyncPluginKey) ||\n transaction.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)\n )\n ) {\n return;\n }\n const transform = combineTransactionSteps(oldState.doc, [\n ...transactions,\n ]);\n const changes = getChangedRanges(transform);\n\n changes.forEach(({ newRange, oldRange }) => {\n const newMentions = getMentionsFromNode(newState.doc, newRange);\n const oldMentions = getMentionsFromNode(oldState.doc, oldRange);\n\n if (oldMentions.size || newMentions.size) {\n // create new mentions\n newMentions.forEach((mention) => {\n if (!oldMentions.has(mention.notificationId)) {\n onCreateMention(mention);\n }\n });\n // delete old mentions\n oldMentions.forEach((mention) => {\n if (!newMentions.has(mention.notificationId)) {\n onDeleteMention(mention.notificationId);\n }\n });\n }\n });\n\n return undefined;\n },\n });\n};\n\nexport const MentionExtension = Extension.create<MentionExtensionOptions>({\n name: LIVEBLOCKS_MENTION_EXTENSION,\n\n priority: 101,\n addOptions() {\n return {\n onCreateMention: () => {},\n onDeleteMention: () => {},\n };\n },\n\n addExtensions() {\n return [MentionNode, GroupMentionNode];\n },\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n editor: this.editor,\n char: MENTION_CHARACTER,\n pluginKey: LIVEBLOCKS_MENTION_KEY,\n command: ({ editor, range, props }) => {\n // increase range.to by one when the next node is of type \"text\"\n // and starts with a space character\n const nodeAfter = editor.view.state.selection.$to.nodeAfter;\n const overrideSpace = nodeAfter?.text?.startsWith(\" \");\n\n if (overrideSpace) {\n range.to += 1;\n }\n\n const mention = props as TiptapMentionData;\n\n let mentionNode: Content;\n\n if (mention.kind === \"user\") {\n mentionNode = {\n type: LIVEBLOCKS_MENTION_TYPE,\n attrs: {\n id: mention.id,\n notificationId: mention.notificationId,\n },\n };\n } else if (mention.kind === \"group\") {\n mentionNode = {\n type: LIVEBLOCKS_GROUP_MENTION_TYPE,\n attrs: {\n id: mention.id,\n userIds: mention.userIds\n ? JSON.stringify(mention.userIds)\n : undefined,\n notificationId: mention.notificationId,\n },\n };\n } else {\n assertNever(mention, \"Unhandled mention kind\");\n }\n\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n mentionNode,\n {\n type: \"text\",\n text: \" \",\n },\n ])\n .run();\n\n // get reference to `window` object from editor element, to support cross-frame JS usage\n editor.view.dom.ownerDocument.defaultView\n ?.getSelection()\n ?.collapseToEnd();\n },\n allow: ({ state, range }) => {\n const $fromParentType = state.doc.resolve(range.from).parent.type;\n\n return Boolean(\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_MENTION_TYPE]\n ) ||\n $fromParentType.contentMatch.matchType(\n state.schema.nodes[LIVEBLOCKS_GROUP_MENTION_TYPE]\n )\n );\n },\n allowSpaces: true,\n items: () => [], // we'll let the mentions list component do this\n render: () => {\n let component: ReactRenderer<MentionsListHandle, MentionsListProps>;\n return {\n onStart: (props) => {\n component = new ReactRenderer<\n MentionsListHandle,\n MentionsListProps\n >(MentionsList, {\n props,\n editor: props.editor,\n });\n\n if (!props.clientRect) {\n return;\n }\n\n document.body.appendChild(component.element);\n },\n\n onUpdate(props) {\n component.updateProps(props);\n },\n\n onKeyDown(props) {\n if (props.event.key === \"Escape\") {\n component.updateProps({\n ...props,\n hide: true,\n });\n return true;\n }\n return component.ref?.onKeyDown(props) ?? false;\n },\n\n onExit() {\n if (document.body.contains(component.element)) {\n document.body.removeChild(component.element);\n }\n component.destroy();\n },\n };\n },\n }),\n notifier(this.options),\n mentionPasteHandler(),\n ];\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAwCA,MAAM,sBAAsB,MAAc;AACxC,EAAA,OAAO,IAAI,MAAO,CAAA;AAAA,IAChB,GAAK,EAAA,4BAAA;AAAA,IACL,KAAO,EAAA;AAAA,MACL,eAAA,EAAiB,CAAC,KAAU,KAAA;AAC1B,QAAM,MAAA,qBAAA,GAAwB,CAAC,IAA0B,KAAA;AAEvD,UAAA,IACE,KAAK,IAAK,CAAA,IAAA,KAAS,2BACnB,IAAK,CAAA,IAAA,CAAK,SAAS,6BACnB,EAAA;AACA,YAAA,OAAO,KAAK,IAAK,CAAA,MAAA;AAAA,cACf,EAAE,GAAG,IAAA,CAAK,KAAO,EAAA,cAAA,EAAgB,2BAA4B,EAAA;AAAA,cAC7D,IAAK,CAAA,OAAA;AAAA,aACP,CAAA;AAAA,WACF;AACA,UAAO,OAAA,IAAA,CAAK,IAAK,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,SAC/B,CAAA;AACA,QAAA,MAAM,QAAW,GAAA,WAAA,CAAY,KAAM,CAAA,OAAA,EAAS,qBAAqB,CAAA,CAAA;AACjE,QAAA,OAAO,IAAI,KAAM,CAAA,QAAA,EAAU,KAAM,CAAA,SAAA,EAAW,MAAM,OAAO,CAAA,CAAA;AAAA,OAC3D;AAAA,KACF;AAAA,GACD,CAAA,CAAA;AACH,CAAA,CAAA;AAYA,MAAM,WAAW,CAAC;AAAA,EAChB,eAAA;AAAA,EACA,eAAA;AACF,CAAuC,KAAA;AACrC,EAAA,OAAO,IAAI,MAAO,CAAA;AAAA,IAChB,GAAK,EAAA,+BAAA;AAAA,IACL,iBAAmB,EAAA,CAAC,YAAc,EAAA,QAAA,EAAU,QAAa,KAAA;AACvD,MAAA,MAAM,UACJ,GAAA,YAAA,CAAa,IAAK,CAAA,CAAC,WAAgB,KAAA,WAAA,CAAY,UAAU,CAAA,IACzD,CAAC,QAAA,CAAS,GAAI,CAAA,EAAA,CAAG,SAAS,GAAG,CAAA,CAAA;AAE/B,MAAA,IAAI,CAAC,UAAY,EAAA;AACf,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,IACE,YAAa,CAAA,IAAA;AAAA,QACX,CAAC,gBACC,WAAY,CAAA,OAAA,CAAQ,cAAc,CAClC,IAAA,WAAA,CAAY,QAAQ,mCAAmC,CAAA;AAAA,OAE3D,EAAA;AACA,QAAA,OAAA;AAAA,OACF;AACA,MAAM,MAAA,SAAA,GAAY,uBAAwB,CAAA,QAAA,CAAS,GAAK,EAAA;AAAA,QACtD,GAAG,YAAA;AAAA,OACJ,CAAA,CAAA;AACD,MAAM,MAAA,OAAA,GAAU,iBAAiB,SAAS,CAAA,CAAA;AAE1C,MAAA,OAAA,CAAQ,OAAQ,CAAA,CAAC,EAAE,QAAA,EAAU,UAAe,KAAA;AAC1C,QAAA,MAAM,WAAc,GAAA,mBAAA,CAAoB,QAAS,CAAA,GAAA,EAAK,QAAQ,CAAA,CAAA;AAC9D,QAAA,MAAM,WAAc,GAAA,mBAAA,CAAoB,QAAS,CAAA,GAAA,EAAK,QAAQ,CAAA,CAAA;AAE9D,QAAI,IAAA,WAAA,CAAY,IAAQ,IAAA,WAAA,CAAY,IAAM,EAAA;AAExC,UAAY,WAAA,CAAA,OAAA,CAAQ,CAAC,OAAY,KAAA;AAC/B,YAAA,IAAI,CAAC,WAAA,CAAY,GAAI,CAAA,OAAA,CAAQ,cAAc,CAAG,EAAA;AAC5C,cAAA,eAAA,CAAgB,OAAO,CAAA,CAAA;AAAA,aACzB;AAAA,WACD,CAAA,CAAA;AAED,UAAY,WAAA,CAAA,OAAA,CAAQ,CAAC,OAAY,KAAA;AAC/B,YAAA,IAAI,CAAC,WAAA,CAAY,GAAI,CAAA,OAAA,CAAQ,cAAc,CAAG,EAAA;AAC5C,cAAA,eAAA,CAAgB,QAAQ,cAAc,CAAA,CAAA;AAAA,aACxC;AAAA,WACD,CAAA,CAAA;AAAA,SACH;AAAA,OACD,CAAA,CAAA;AAED,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACT;AAAA,GACD,CAAA,CAAA;AACH,CAAA,CAAA;AAEa,MAAA,gBAAA,GAAmB,UAAU,MAAgC,CAAA;AAAA,EACxE,IAAM,EAAA,4BAAA;AAAA,EAEN,QAAU,EAAA,GAAA;AAAA,EACV,UAAa,GAAA;AACX,IAAO,OAAA;AAAA,MACL,iBAAiB,MAAM;AAAA,OAAC;AAAA,MACxB,iBAAiB,MAAM;AAAA,OAAC;AAAA,KAC1B,CAAA;AAAA,GACF;AAAA,EAEA,aAAgB,GAAA;AACd,IAAO,OAAA,CAAC,aAAa,gBAAgB,CAAA,CAAA;AAAA,GACvC;AAAA,EAEA,qBAAwB,GAAA;AACtB,IAAO,OAAA;AAAA,MACL,UAAW,CAAA;AAAA,QACT,QAAQ,IAAK,CAAA,MAAA;AAAA,QACb,IAAM,EAAA,iBAAA;AAAA,QACN,SAAW,EAAA,sBAAA;AAAA,QACX,SAAS,CAAC,EAAE,MAAQ,EAAA,KAAA,EAAO,OAAY,KAAA;AAGrC,UAAA,MAAM,SAAY,GAAA,MAAA,CAAO,IAAK,CAAA,KAAA,CAAM,UAAU,GAAI,CAAA,SAAA,CAAA;AAClD,UAAA,MAAM,aAAgB,GAAA,SAAA,EAAW,IAAM,EAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AAErD,UAAA,IAAI,aAAe,EAAA;AACjB,YAAA,KAAA,CAAM,EAAM,IAAA,CAAA,CAAA;AAAA,WACd;AAEA,UAAA,MAAM,OAAU,GAAA,KAAA,CAAA;AAEhB,UAAI,IAAA,WAAA,CAAA;AAEJ,UAAI,IAAA,OAAA,CAAQ,SAAS,MAAQ,EAAA;AAC3B,YAAc,WAAA,GAAA;AAAA,cACZ,IAAM,EAAA,uBAAA;AAAA,cACN,KAAO,EAAA;AAAA,gBACL,IAAI,OAAQ,CAAA,EAAA;AAAA,gBACZ,gBAAgB,OAAQ,CAAA,cAAA;AAAA,eAC1B;AAAA,aACF,CAAA;AAAA,WACF,MAAA,IAAW,OAAQ,CAAA,IAAA,KAAS,OAAS,EAAA;AACnC,YAAc,WAAA,GAAA;AAAA,cACZ,IAAM,EAAA,6BAAA;AAAA,cACN,KAAO,EAAA;AAAA,gBACL,IAAI,OAAQ,CAAA,EAAA;AAAA,gBACZ,SAAS,OAAQ,CAAA,OAAA,GACb,KAAK,SAAU,CAAA,OAAA,CAAQ,OAAO,CAC9B,GAAA,KAAA,CAAA;AAAA,gBACJ,gBAAgB,OAAQ,CAAA,cAAA;AAAA,eAC1B;AAAA,aACF,CAAA;AAAA,WACK,MAAA;AACL,YAAA,WAAA,CAAY,SAAS,wBAAwB,CAAA,CAAA;AAAA,WAC/C;AAEA,UAAA,MAAA,CACG,KAAM,EAAA,CACN,KAAM,EAAA,CACN,gBAAgB,KAAO,EAAA;AAAA,YACtB,WAAA;AAAA,YACA;AAAA,cACE,IAAM,EAAA,MAAA;AAAA,cACN,IAAM,EAAA,GAAA;AAAA,aACR;AAAA,WACD,EACA,GAAI,EAAA,CAAA;AAGP,UAAA,MAAA,CAAO,KAAK,GAAI,CAAA,aAAA,CAAc,WAC1B,EAAA,YAAA,IACA,aAAc,EAAA,CAAA;AAAA,SACpB;AAAA,QACA,KAAO,EAAA,CAAC,EAAE,KAAA,EAAO,OAAY,KAAA;AAC3B,UAAA,MAAM,kBAAkB,KAAM,CAAA,GAAA,CAAI,QAAQ,KAAM,CAAA,IAAI,EAAE,MAAO,CAAA,IAAA,CAAA;AAE7D,UAAO,OAAA,OAAA;AAAA,YACL,gBAAgB,YAAa,CAAA,SAAA;AAAA,cAC3B,KAAA,CAAM,MAAO,CAAA,KAAA,CAAM,uBAAuB,CAAA;AAAA,aAC5C,IACA,gBAAgB,YAAa,CAAA,SAAA;AAAA,cAC3B,KAAA,CAAM,MAAO,CAAA,KAAA,CAAM,6BAA6B,CAAA;AAAA,aAClD;AAAA,WACF,CAAA;AAAA,SACF;AAAA,QACA,WAAa,EAAA,IAAA;AAAA,QACb,KAAA,EAAO,MAAM,EAAC;AAAA;AAAA,QACd,QAAQ,MAAM;AACZ,UAAI,IAAA,SAAA,CAAA;AACJ,UAAO,OAAA;AAAA,YACL,OAAA,EAAS,CAAC,KAAU,KAAA;AAClB,cAAY,SAAA,GAAA,IAAI,cAGd,YAAc,EAAA;AAAA,gBACd,KAAA;AAAA,gBACA,QAAQ,KAAM,CAAA,MAAA;AAAA,eACf,CAAA,CAAA;AAED,cAAI,IAAA,CAAC,MAAM,UAAY,EAAA;AACrB,gBAAA,OAAA;AAAA,eACF;AAEA,cAAS,QAAA,CAAA,IAAA,CAAK,WAAY,CAAA,SAAA,CAAU,OAAO,CAAA,CAAA;AAAA,aAC7C;AAAA,YAEA,SAAS,KAAO,EAAA;AACd,cAAA,SAAA,CAAU,YAAY,KAAK,CAAA,CAAA;AAAA,aAC7B;AAAA,YAEA,UAAU,KAAO,EAAA;AACf,cAAI,IAAA,KAAA,CAAM,KAAM,CAAA,GAAA,KAAQ,QAAU,EAAA;AAChC,gBAAA,SAAA,CAAU,WAAY,CAAA;AAAA,kBACpB,GAAG,KAAA;AAAA,kBACH,IAAM,EAAA,IAAA;AAAA,iBACP,CAAA,CAAA;AACD,gBAAO,OAAA,IAAA,CAAA;AAAA,eACT;AACA,cAAA,OAAO,SAAU,CAAA,GAAA,EAAK,SAAU,CAAA,KAAK,CAAK,IAAA,KAAA,CAAA;AAAA,aAC5C;AAAA,YAEA,MAAS,GAAA;AACP,cAAA,IAAI,QAAS,CAAA,IAAA,CAAK,QAAS,CAAA,SAAA,CAAU,OAAO,CAAG,EAAA;AAC7C,gBAAS,QAAA,CAAA,IAAA,CAAK,WAAY,CAAA,SAAA,CAAU,OAAO,CAAA,CAAA;AAAA,eAC7C;AACA,cAAA,SAAA,CAAU,OAAQ,EAAA,CAAA;AAAA,aACpB;AAAA,WACF,CAAA;AAAA,SACF;AAAA,OACD,CAAA;AAAA,MACD,QAAA,CAAS,KAAK,OAAO,CAAA;AAAA,MACrB,mBAAoB,EAAA;AAAA,KACtB,CAAA;AAAA,GACF;AACF,CAAC;;;;"}
|
package/dist/version.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const PKG_NAME = "@liveblocks/react-tiptap";
|
|
4
|
-
const PKG_VERSION = typeof "3.21.0-
|
|
4
|
+
const PKG_VERSION = typeof "3.21.0-exp3" === "string" && "3.21.0-exp3";
|
|
5
5
|
const PKG_FORMAT = typeof "cjs" === "string" && "cjs";
|
|
6
6
|
|
|
7
7
|
exports.PKG_FORMAT = PKG_FORMAT;
|
package/dist/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const PKG_NAME = "@liveblocks/react-tiptap";
|
|
2
|
-
const PKG_VERSION = typeof "3.21.0-
|
|
2
|
+
const PKG_VERSION = typeof "3.21.0-exp3" === "string" && "3.21.0-exp3";
|
|
3
3
|
const PKG_FORMAT = typeof "esm" === "string" && "esm";
|
|
4
4
|
|
|
5
5
|
export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/react-tiptap",
|
|
3
|
-
"version": "3.21.0-
|
|
3
|
+
"version": "3.21.0-exp3",
|
|
4
4
|
"description": "An integration of TipTap + React to enable collaboration, comments, live cursors, and more with Liveblocks.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Liveblocks Inc.",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"cmdk": "^1.0.4",
|
|
38
38
|
"radix-ui": "^1.4.0",
|
|
39
39
|
"y-prosemirror": "^1.3.7",
|
|
40
|
-
"@liveblocks/client": "3.21.0-
|
|
41
|
-
"@liveblocks/
|
|
42
|
-
"@liveblocks/core": "3.21.0-
|
|
43
|
-
"@liveblocks/react
|
|
44
|
-
"@liveblocks/
|
|
40
|
+
"@liveblocks/client": "3.21.0-exp3",
|
|
41
|
+
"@liveblocks/prosemirror": "3.20.0",
|
|
42
|
+
"@liveblocks/core": "3.21.0-exp3",
|
|
43
|
+
"@liveblocks/react": "3.21.0-exp3",
|
|
44
|
+
"@liveblocks/react-ui": "3.21.0-exp3",
|
|
45
|
+
"@liveblocks/yjs": "3.21.0-exp3"
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"@tiptap/core": "^3",
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var schema = require('./schema.cjs');
|
|
4
|
-
|
|
5
|
-
function selectionToLiveblocksPosition(selection) {
|
|
6
|
-
return {
|
|
7
|
-
anchor: selection.anchor,
|
|
8
|
-
head: selection.head
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
function clampLiveblocksPosition(position, max) {
|
|
12
|
-
return {
|
|
13
|
-
anchor: Math.max(0, Math.min(position.anchor, max)),
|
|
14
|
-
head: Math.max(0, Math.min(position.head, max))
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function childStart(parent, parentPos) {
|
|
18
|
-
return parent.type.name === "doc" ? parentPos : parentPos + 1;
|
|
19
|
-
}
|
|
20
|
-
function indexChildren(nodeRanges, listRanges, textRanges, pmParent, liveParent, parentPos) {
|
|
21
|
-
const liveContent = schema.getLiveblocksNodeContent(liveParent);
|
|
22
|
-
if (liveContent === void 0) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
listRanges.push({
|
|
26
|
-
content: liveContent,
|
|
27
|
-
from: parentPos,
|
|
28
|
-
node: liveParent,
|
|
29
|
-
nodeId: schema.getLiveblocksNodeId(liveParent),
|
|
30
|
-
pmNode: pmParent,
|
|
31
|
-
to: parentPos + pmParent.nodeSize
|
|
32
|
-
});
|
|
33
|
-
let pmChildIndex = 0;
|
|
34
|
-
let pmOffset = 0;
|
|
35
|
-
const start = childStart(pmParent, parentPos);
|
|
36
|
-
for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {
|
|
37
|
-
const liveChild = liveContent.get(liveIndex);
|
|
38
|
-
const pmChild = pmParent.maybeChild(pmChildIndex);
|
|
39
|
-
if (liveChild === void 0 || pmChild === null) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const from = start + pmOffset;
|
|
43
|
-
const to = from + pmChild.nodeSize;
|
|
44
|
-
nodeRanges.push({
|
|
45
|
-
childIndex: liveIndex,
|
|
46
|
-
content: liveContent,
|
|
47
|
-
from,
|
|
48
|
-
node: liveChild,
|
|
49
|
-
nodeId: schema.getLiveblocksNodeId(liveChild),
|
|
50
|
-
parent: liveParent,
|
|
51
|
-
pmNode: pmChild,
|
|
52
|
-
to
|
|
53
|
-
});
|
|
54
|
-
if (schema.getLiveblocksNodeType(liveChild) === "text") {
|
|
55
|
-
const text = schema.getLiveblocksNodeText(liveChild);
|
|
56
|
-
if (text === void 0) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
let liveOffset = 0;
|
|
60
|
-
let remaining = text.length;
|
|
61
|
-
while (remaining > 0) {
|
|
62
|
-
const textChild = pmParent.maybeChild(pmChildIndex);
|
|
63
|
-
if (textChild === null || !textChild.isText) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const length = Math.min(remaining, textChild.nodeSize);
|
|
67
|
-
const textFrom = start + pmOffset;
|
|
68
|
-
textRanges.push({
|
|
69
|
-
from: textFrom,
|
|
70
|
-
to: textFrom + length,
|
|
71
|
-
liveOffset,
|
|
72
|
-
node: liveChild,
|
|
73
|
-
nodeId: schema.getLiveblocksNodeId(liveChild),
|
|
74
|
-
text
|
|
75
|
-
});
|
|
76
|
-
liveOffset += length;
|
|
77
|
-
remaining -= length;
|
|
78
|
-
pmOffset += textChild.nodeSize;
|
|
79
|
-
pmChildIndex++;
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
indexChildren(
|
|
83
|
-
nodeRanges,
|
|
84
|
-
listRanges,
|
|
85
|
-
textRanges,
|
|
86
|
-
pmChild,
|
|
87
|
-
liveChild,
|
|
88
|
-
from
|
|
89
|
-
);
|
|
90
|
-
pmOffset += pmChild.nodeSize;
|
|
91
|
-
pmChildIndex++;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function buildLiveblocksTreeIndex(pmDoc, liveRoot) {
|
|
96
|
-
const nodeRanges = [
|
|
97
|
-
{
|
|
98
|
-
from: 0,
|
|
99
|
-
node: liveRoot,
|
|
100
|
-
nodeId: schema.getLiveblocksNodeId(liveRoot),
|
|
101
|
-
pmNode: pmDoc,
|
|
102
|
-
to: pmDoc.content.size
|
|
103
|
-
}
|
|
104
|
-
];
|
|
105
|
-
const listRanges = [];
|
|
106
|
-
const textRanges = [];
|
|
107
|
-
indexChildren(nodeRanges, listRanges, textRanges, pmDoc, liveRoot, 0);
|
|
108
|
-
return { listRanges, nodeRanges, textRanges };
|
|
109
|
-
}
|
|
110
|
-
function findTextRangeAtPosition(index, position) {
|
|
111
|
-
return index.textRanges.find(
|
|
112
|
-
(range) => position >= range.from && position <= range.to
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
function findTextRangeAtPositionInChildren(pmParent, liveParent, parentPos, position) {
|
|
116
|
-
const liveContent = schema.getLiveblocksNodeContent(liveParent);
|
|
117
|
-
if (liveContent === void 0) {
|
|
118
|
-
return void 0;
|
|
119
|
-
}
|
|
120
|
-
let pmChildIndex = 0;
|
|
121
|
-
let pmOffset = 0;
|
|
122
|
-
const start = childStart(pmParent, parentPos);
|
|
123
|
-
for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {
|
|
124
|
-
const liveChild = liveContent.get(liveIndex);
|
|
125
|
-
const pmChild = pmParent.maybeChild(pmChildIndex);
|
|
126
|
-
if (liveChild === void 0 || pmChild === null) {
|
|
127
|
-
return void 0;
|
|
128
|
-
}
|
|
129
|
-
if (schema.getLiveblocksNodeType(liveChild) === "text") {
|
|
130
|
-
const text = schema.getLiveblocksNodeText(liveChild);
|
|
131
|
-
if (text === void 0) {
|
|
132
|
-
return void 0;
|
|
133
|
-
}
|
|
134
|
-
let liveOffset = 0;
|
|
135
|
-
let remaining = text.length;
|
|
136
|
-
while (remaining > 0) {
|
|
137
|
-
const textChild = pmParent.maybeChild(pmChildIndex);
|
|
138
|
-
if (textChild === null || !textChild.isText) {
|
|
139
|
-
return void 0;
|
|
140
|
-
}
|
|
141
|
-
const length = Math.min(remaining, textChild.nodeSize);
|
|
142
|
-
const from = start + pmOffset;
|
|
143
|
-
const to = from + length;
|
|
144
|
-
if (position >= from && position <= to) {
|
|
145
|
-
return {
|
|
146
|
-
from,
|
|
147
|
-
to,
|
|
148
|
-
liveOffset,
|
|
149
|
-
node: liveChild,
|
|
150
|
-
nodeId: schema.getLiveblocksNodeId(liveChild),
|
|
151
|
-
text
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
liveOffset += length;
|
|
155
|
-
remaining -= length;
|
|
156
|
-
pmOffset += textChild.nodeSize;
|
|
157
|
-
pmChildIndex++;
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
const from = start + pmOffset;
|
|
161
|
-
const to = from + pmChild.nodeSize;
|
|
162
|
-
if (position >= from && position <= to) {
|
|
163
|
-
return findTextRangeAtPositionInChildren(
|
|
164
|
-
pmChild,
|
|
165
|
-
liveChild,
|
|
166
|
-
from,
|
|
167
|
-
position
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
pmOffset += pmChild.nodeSize;
|
|
171
|
-
pmChildIndex++;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return void 0;
|
|
175
|
-
}
|
|
176
|
-
function findTextRangeAtPositionInDocument(pmDoc, liveRoot, position) {
|
|
177
|
-
return findTextRangeAtPositionInChildren(pmDoc, liveRoot, 0, position);
|
|
178
|
-
}
|
|
179
|
-
function findTextRangesInRange(index, from, to) {
|
|
180
|
-
return index.textRanges.filter(
|
|
181
|
-
(range) => Math.max(range.from, from) < Math.min(range.to, to)
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
function findTextRangeByLiveText(index, text) {
|
|
185
|
-
return index.textRanges.find((range) => range.text === text);
|
|
186
|
-
}
|
|
187
|
-
function findNodeRangeByLiveNode(index, node) {
|
|
188
|
-
return index.nodeRanges.find((range) => range.node === node);
|
|
189
|
-
}
|
|
190
|
-
function findListRangeByLiveList(index, content) {
|
|
191
|
-
return index.listRanges.find((range) => range.content === content);
|
|
192
|
-
}
|
|
193
|
-
function getChildPosition(parent, parentPos, index) {
|
|
194
|
-
if (index < 0 || index > parent.childCount) {
|
|
195
|
-
return void 0;
|
|
196
|
-
}
|
|
197
|
-
let offset = 0;
|
|
198
|
-
for (let childIndex = 0; childIndex < index; childIndex++) {
|
|
199
|
-
const child = parent.maybeChild(childIndex);
|
|
200
|
-
if (child === null) {
|
|
201
|
-
return void 0;
|
|
202
|
-
}
|
|
203
|
-
offset += child.nodeSize;
|
|
204
|
-
}
|
|
205
|
-
return childStart(parent, parentPos) + offset;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
exports.buildLiveblocksTreeIndex = buildLiveblocksTreeIndex;
|
|
209
|
-
exports.clampLiveblocksPosition = clampLiveblocksPosition;
|
|
210
|
-
exports.findListRangeByLiveList = findListRangeByLiveList;
|
|
211
|
-
exports.findNodeRangeByLiveNode = findNodeRangeByLiveNode;
|
|
212
|
-
exports.findTextRangeAtPosition = findTextRangeAtPosition;
|
|
213
|
-
exports.findTextRangeAtPositionInDocument = findTextRangeAtPositionInDocument;
|
|
214
|
-
exports.findTextRangeByLiveText = findTextRangeByLiveText;
|
|
215
|
-
exports.findTextRangesInRange = findTextRangesInRange;
|
|
216
|
-
exports.getChildPosition = getChildPosition;
|
|
217
|
-
exports.selectionToLiveblocksPosition = selectionToLiveblocksPosition;
|
|
218
|
-
//# sourceMappingURL=mapping.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mapping.cjs","sources":["../../src/collaboration-liveblocks/mapping.ts"],"sourcesContent":["import type { LiveList, LiveText } from \"@liveblocks/client\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport type { Selection } from \"@tiptap/pm/state\";\n\nimport {\n getLiveblocksNodeContent,\n getLiveblocksNodeId,\n getLiveblocksNodeText,\n getLiveblocksNodeType,\n type LiveblocksTiptapNode,\n} from \"./schema\";\n\nexport type LiveblocksTiptapPosition = {\n anchor: number;\n head: number;\n};\n\nexport function selectionToLiveblocksPosition(\n selection: Selection\n): LiveblocksTiptapPosition {\n return {\n anchor: selection.anchor,\n head: selection.head,\n };\n}\n\nexport function clampLiveblocksPosition(\n position: LiveblocksTiptapPosition,\n max: number\n): LiveblocksTiptapPosition {\n return {\n anchor: Math.max(0, Math.min(position.anchor, max)),\n head: Math.max(0, Math.min(position.head, max)),\n };\n}\n\nexport type LiveblocksTextRange = {\n from: number;\n to: number;\n liveOffset: number;\n node: LiveblocksTiptapNode;\n nodeId: string;\n text: LiveText;\n};\n\nexport type LiveblocksNodeRange = {\n childIndex?: number;\n content?: LiveList<LiveblocksTiptapNode>;\n from: number;\n node: LiveblocksTiptapNode;\n nodeId: string;\n parent?: LiveblocksTiptapNode;\n pmNode: ProseMirrorNode;\n to: number;\n};\n\nexport type LiveblocksListRange = {\n content: LiveList<LiveblocksTiptapNode>;\n from: number;\n node: LiveblocksTiptapNode;\n nodeId: string;\n pmNode: ProseMirrorNode;\n to: number;\n};\n\nexport type LiveblocksTreeIndex = {\n listRanges: LiveblocksListRange[];\n nodeRanges: LiveblocksNodeRange[];\n textRanges: LiveblocksTextRange[];\n};\n\nfunction childStart(parent: ProseMirrorNode, parentPos: number): number {\n return parent.type.name === \"doc\" ? parentPos : parentPos + 1;\n}\n\nfunction indexChildren(\n nodeRanges: LiveblocksNodeRange[],\n listRanges: LiveblocksListRange[],\n textRanges: LiveblocksTextRange[],\n pmParent: ProseMirrorNode,\n liveParent: LiveblocksTiptapNode,\n parentPos: number\n): void {\n const liveContent = getLiveblocksNodeContent(liveParent);\n if (liveContent === undefined) {\n return;\n }\n\n listRanges.push({\n content: liveContent,\n from: parentPos,\n node: liveParent,\n nodeId: getLiveblocksNodeId(liveParent),\n pmNode: pmParent,\n to: parentPos + pmParent.nodeSize,\n });\n\n let pmChildIndex = 0;\n let pmOffset = 0;\n const start = childStart(pmParent, parentPos);\n\n for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {\n const liveChild = liveContent.get(liveIndex);\n const pmChild = pmParent.maybeChild(pmChildIndex);\n if (liveChild === undefined || pmChild === null) {\n return;\n }\n\n const from = start + pmOffset;\n const to = from + pmChild.nodeSize;\n\n nodeRanges.push({\n childIndex: liveIndex,\n content: liveContent,\n from,\n node: liveChild,\n nodeId: getLiveblocksNodeId(liveChild),\n parent: liveParent,\n pmNode: pmChild,\n to,\n });\n\n if (getLiveblocksNodeType(liveChild) === \"text\") {\n const text = getLiveblocksNodeText(liveChild);\n if (text === undefined) {\n return;\n }\n\n let liveOffset = 0;\n let remaining = text.length;\n\n while (remaining > 0) {\n const textChild = pmParent.maybeChild(pmChildIndex);\n if (textChild === null || !textChild.isText) {\n return;\n }\n\n const length = Math.min(remaining, textChild.nodeSize);\n const textFrom = start + pmOffset;\n\n textRanges.push({\n from: textFrom,\n to: textFrom + length,\n liveOffset,\n node: liveChild,\n nodeId: getLiveblocksNodeId(liveChild),\n text,\n });\n\n liveOffset += length;\n remaining -= length;\n pmOffset += textChild.nodeSize;\n pmChildIndex++;\n }\n } else {\n indexChildren(\n nodeRanges,\n listRanges,\n textRanges,\n pmChild,\n liveChild,\n from\n );\n pmOffset += pmChild.nodeSize;\n pmChildIndex++;\n }\n }\n}\n\nexport function buildLiveblocksTreeIndex(\n pmDoc: ProseMirrorNode,\n liveRoot: LiveblocksTiptapNode\n): LiveblocksTreeIndex {\n const nodeRanges: LiveblocksNodeRange[] = [\n {\n from: 0,\n node: liveRoot,\n nodeId: getLiveblocksNodeId(liveRoot),\n pmNode: pmDoc,\n to: pmDoc.content.size,\n },\n ];\n const listRanges: LiveblocksListRange[] = [];\n const textRanges: LiveblocksTextRange[] = [];\n indexChildren(nodeRanges, listRanges, textRanges, pmDoc, liveRoot, 0);\n return { listRanges, nodeRanges, textRanges };\n}\n\nexport function findTextRangeAtPosition(\n index: LiveblocksTreeIndex,\n position: number\n): LiveblocksTextRange | undefined {\n return index.textRanges.find(\n (range) => position >= range.from && position <= range.to\n );\n}\n\nfunction findTextRangeAtPositionInChildren(\n pmParent: ProseMirrorNode,\n liveParent: LiveblocksTiptapNode,\n parentPos: number,\n position: number\n): LiveblocksTextRange | undefined {\n const liveContent = getLiveblocksNodeContent(liveParent);\n if (liveContent === undefined) {\n return undefined;\n }\n\n let pmChildIndex = 0;\n let pmOffset = 0;\n const start = childStart(pmParent, parentPos);\n\n for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {\n const liveChild = liveContent.get(liveIndex);\n const pmChild = pmParent.maybeChild(pmChildIndex);\n if (liveChild === undefined || pmChild === null) {\n return undefined;\n }\n\n if (getLiveblocksNodeType(liveChild) === \"text\") {\n const text = getLiveblocksNodeText(liveChild);\n if (text === undefined) {\n return undefined;\n }\n\n let liveOffset = 0;\n let remaining = text.length;\n\n while (remaining > 0) {\n const textChild = pmParent.maybeChild(pmChildIndex);\n if (textChild === null || !textChild.isText) {\n return undefined;\n }\n\n const length = Math.min(remaining, textChild.nodeSize);\n const from = start + pmOffset;\n const to = from + length;\n\n if (position >= from && position <= to) {\n return {\n from,\n to,\n liveOffset,\n node: liveChild,\n nodeId: getLiveblocksNodeId(liveChild),\n text,\n };\n }\n\n liveOffset += length;\n remaining -= length;\n pmOffset += textChild.nodeSize;\n pmChildIndex++;\n }\n } else {\n const from = start + pmOffset;\n const to = from + pmChild.nodeSize;\n\n if (position >= from && position <= to) {\n return findTextRangeAtPositionInChildren(\n pmChild,\n liveChild,\n from,\n position\n );\n }\n\n pmOffset += pmChild.nodeSize;\n pmChildIndex++;\n }\n }\n\n return undefined;\n}\n\nexport function findTextRangeAtPositionInDocument(\n pmDoc: ProseMirrorNode,\n liveRoot: LiveblocksTiptapNode,\n position: number\n): LiveblocksTextRange | undefined {\n return findTextRangeAtPositionInChildren(pmDoc, liveRoot, 0, position);\n}\n\nexport function findTextRangesInRange(\n index: LiveblocksTreeIndex,\n from: number,\n to: number\n): LiveblocksTextRange[] {\n return index.textRanges.filter(\n (range) => Math.max(range.from, from) < Math.min(range.to, to)\n );\n}\n\nexport function findTextRangeByLiveText(\n index: LiveblocksTreeIndex,\n text: LiveText\n): LiveblocksTextRange | undefined {\n return index.textRanges.find((range) => range.text === text);\n}\n\nexport function findNodeRangeByLiveNode(\n index: LiveblocksTreeIndex,\n node: LiveblocksTiptapNode\n): LiveblocksNodeRange | undefined {\n return index.nodeRanges.find((range) => range.node === node);\n}\n\nexport function findListRangeByLiveList(\n index: LiveblocksTreeIndex,\n content: unknown\n): LiveblocksListRange | undefined {\n return index.listRanges.find((range) => range.content === content);\n}\n\nexport function getChildPosition(\n parent: ProseMirrorNode,\n parentPos: number,\n index: number\n): number | undefined {\n if (index < 0 || index > parent.childCount) {\n return undefined;\n }\n\n let offset = 0;\n for (let childIndex = 0; childIndex < index; childIndex++) {\n const child = parent.maybeChild(childIndex);\n if (child === null) {\n return undefined;\n }\n\n offset += child.nodeSize;\n }\n\n return childStart(parent, parentPos) + offset;\n}\n"],"names":["getLiveblocksNodeContent","getLiveblocksNodeId","getLiveblocksNodeType","getLiveblocksNodeText"],"mappings":"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"}
|