@blocknote/core 0.27.2 → 0.28.0
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/blocknote.cjs +10 -10
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +1327 -1283
- package/dist/blocknote.js.map +1 -1
- package/dist/locales.cjs +1 -1
- package/dist/locales.cjs.map +1 -1
- package/dist/locales.js +10 -10
- package/dist/locales.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +1 -1
- package/src/api/positionMapping.test.ts +370 -0
- package/src/api/positionMapping.ts +112 -0
- package/src/editor/BlockNoteEditor.ts +1 -0
- package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +17 -7
- package/src/i18n/locales/de.ts +10 -10
- package/types/src/api/positionMapping.d.ts +25 -0
- package/types/src/api/positionMapping.test.d.ts +1 -0
package/dist/webpack-stats.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"builtAt":1743885337120,"assets":[{"name":"blocknote.cjs","size":179331},{"name":"comments.cjs","size":11826},{"name":"locales.cjs","size":111456},{"name":"en-D4taoCs4.cjs","size":5539},{"name":"en-D4taoCs4.cjs.map","size":12801},{"name":"comments.cjs.map","size":47589},{"name":"locales.cjs.map","size":233666},{"name":"blocknote.cjs.map","size":844054}],"chunks":[{"id":"a1ee98a","entry":true,"initial":true,"files":["blocknote.cjs"],"names":["blocknote"]},{"id":"1627b02","entry":true,"initial":true,"files":["comments.cjs"],"names":["comments"]},{"id":"9eaffe2","entry":true,"initial":true,"files":["locales.cjs"],"names":["locales"]},{"id":"a1e239a","entry":false,"initial":true,"files":["en-D4taoCs4.cjs"],"names":["en"]}],"modules":[{"name":"./src/util/typescript.ts","size":331,"chunks":["a1ee98a"]},{"name":"./src/api/getBlockInfoFromPos.ts","size":3648,"chunks":["a1ee98a"]},{"name":"./src/extensions/UniqueID/UniqueID.ts","size":9054,"chunks":["a1ee98a"]},{"name":"./src/schema/inlineContent/types.ts","size":302,"chunks":["a1ee98a"]},{"name":"./src/util/table.ts","size":1212,"chunks":["a1ee98a"]},{"name":"./src/util/browser.ts","size":536,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultBlockHelpers.ts","size":1755,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultProps.ts","size":269,"chunks":["a1ee98a"]},{"name":"./src/util/string.ts","size":299,"chunks":["a1ee98a"]},{"name":"./src/schema/blocks/internal.ts","size":4130,"chunks":["a1ee98a"]},{"name":"./src/schema/blocks/createSpec.ts","size":3609,"chunks":["a1ee98a"]},{"name":"./src/api/nodeConversions/nodeToBlock.ts","size":9521,"chunks":["a1ee98a"]},{"name":"./src/schema/inlineContent/internal.ts","size":1398,"chunks":["a1ee98a"]},{"name":"./src/schema/inlineContent/createSpec.ts","size":2739,"chunks":["a1ee98a"]},{"name":"./src/schema/styles/internal.ts","size":1162,"chunks":["a1ee98a"]},{"name":"./src/schema/styles/createSpec.ts","size":1263,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/tables/tables.ts","size":10346,"chunks":["a1ee98a"]},{"name":"./src/api/nodeConversions/blockToNode.ts","size":6874,"chunks":["a1ee98a"]},{"name":"./src/api/nodeUtil.ts","size":490,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/updateBlock/updateBlock.ts","size":4754,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/util/serializeBlocksExternalHTML.ts","size":5160,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/externalHTMLExporter.ts","size":886,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/util/serializeBlocksInternalHTML.ts","size":3264,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/internalHTMLSerializer.ts","size":288,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/parse/parseFigureElement.ts","size":342,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts","size":1725,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.ts","size":753,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts","size":1428,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.ts","size":307,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.ts","size":294,"chunks":["a1ee98a"]},{"name":"./src/blocks/AudioBlockContent/parseAudioElement.ts","size":108,"chunks":["a1ee98a"]},{"name":"./src/blocks/AudioBlockContent/AudioBlockContent.ts","size":3155,"chunks":["a1ee98a"]},{"name":"./src/blocks/CodeBlockContent/CodeBlockContent.ts","size":9013,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/parse/parseEmbedElement.ts","size":108,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/FileBlockContent.ts","size":1460,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts","size":4637,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts","size":316,"chunks":["a1ee98a"]},{"name":"./src/blocks/ImageBlockContent/parseImageElement.ts","size":175,"chunks":["a1ee98a"]},{"name":"./src/blocks/ImageBlockContent/ImageBlockContent.ts","size":3243,"chunks":["a1ee98a"]},{"name":"./src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts","size":854,"chunks":["a1ee98a"]},{"name":"./src/extensions/BackgroundColor/BackgroundColorMark.ts","size":946,"chunks":["a1ee98a"]},{"name":"./src/extensions/TextColor/TextColorMark.ts","size":866,"chunks":["a1ee98a"]},{"name":"./src/blocks/HeadingBlockContent/HeadingBlockContent.ts","size":3418,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/splitBlock/splitBlock.ts","size":868,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts","size":1429,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts","size":3415,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts","size":7148,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts","size":2207,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts","size":4427,"chunks":["a1ee98a"]},{"name":"./src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts","size":1434,"chunks":["a1ee98a"]},{"name":"./src/blocks/QuoteBlockContent/QuoteBlockContent.ts","size":1927,"chunks":["a1ee98a"]},{"name":"./src/blocks/TableBlockContent/TableExtension.ts","size":2297,"chunks":["a1ee98a"]},{"name":"./src/blocks/TableBlockContent/TableBlockContent.ts","size":4708,"chunks":["a1ee98a"]},{"name":"./src/blocks/VideoBlockContent/parseVideoElement.ts","size":175,"chunks":["a1ee98a"]},{"name":"./src/blocks/VideoBlockContent/VideoBlockContent.ts","size":3162,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultBlocks.ts","size":1163,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultBlockTypeGuards.ts","size":1688,"chunks":["a1ee98a"]},{"name":"./src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts","size":7072,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteSchema.ts","size":1044,"chunks":["a1ee98a"]},{"name":"./src/blocks/PageBreakBlockContent/schema.ts","size":350,"chunks":["a1ee98a"]},{"name":"./src/blocks/PageBreakBlockContent/getPageBreakSlashMenuItems.ts","size":536,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts","size":1141,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts","size":5693,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/nestBlock/nestBlock.ts","size":2324,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts","size":2533,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts","size":123,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/getBlock/getBlock.ts","size":2452,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/insertContentAt.ts","size":1120,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/selections/selection.ts","size":4698,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts","size":2880,"chunks":["a1ee98a"]},{"name":"./src/util/esmDependencies.ts","size":820,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/markdown/removeUnderlinesRehypePlugin.ts","size":752,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts","size":969,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/markdown/markdownExporter.ts","size":837,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/html/util/nestedLists.ts","size":2174,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/html/parseHTML.ts","size":503,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/markdown/parseMarkdown.ts","size":1201,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/acceptedMIMETypes.ts","size":134,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/handleFileInsertion.ts","size":3917,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/fileDropExtension.ts","size":884,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/handleVSCodePaste.ts","size":661,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/markdown/detectMarkdown.ts","size":1112,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/pasteExtension.ts","size":2109,"chunks":["a1ee98a"]},{"name":"./src/api/nodeConversions/fragmentToBlocks.ts","size":859,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/toClipboard/copyExtension.ts","size":5228,"chunks":["a1ee98a"]},{"name":"./src/extensions/BackgroundColor/BackgroundColorExtension.ts","size":819,"chunks":["a1ee98a"]},{"name":"./src/extensions/Collaboration/createCollaborationExtensions.ts","size":3553,"chunks":["a1ee98a"]},{"name":"./src/extensions/Comments/CommentMark.ts","size":1428,"chunks":["a1ee98a"]},{"name":"./src/util/EventEmitter.ts","size":744,"chunks":["a1ee98a"]},{"name":"./src/extensions/Comments/userstore/UserStore.ts","size":1354,"chunks":["a1ee98a"]},{"name":"./src/extensions/Comments/CommentsPlugin.ts","size":7656,"chunks":["a1ee98a"]},{"name":"./src/extensions/FilePanel/FilePanelPlugin.ts","size":3584,"chunks":["a1ee98a"]},{"name":"./src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts","size":5323,"chunks":["a1ee98a"]},{"name":"./src/extensions/HardBreak/HardBreak.ts","size":376,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts","size":3228,"chunks":["a1ee98a"]},{"name":"./src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts","size":18010,"chunks":["a1ee98a"]},{"name":"./src/extensions/LinkToolbar/LinkToolbarPlugin.ts","size":7611,"chunks":["a1ee98a"]},{"name":"./src/extensions/LinkToolbar/protocols.ts","size":172,"chunks":["a1ee98a"]},{"name":"./src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts","size":1195,"chunks":["a1ee98a"]},{"name":"./src/extensions/Placeholder/PlaceholderPlugin.ts","size":3609,"chunks":["a1ee98a"]},{"name":"./src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts","size":4826,"chunks":["a1ee98a"]},{"name":"./src/extensions/ShowSelection/ShowSelectionPlugin.ts","size":967,"chunks":["a1ee98a"]},{"name":"./src/extensions/getDraggableBlockFromElement.ts","size":404,"chunks":["a1ee98a"]},{"name":"./src/extensions/SideMenu/MultipleNodeSelection.ts","size":1616,"chunks":["a1ee98a"]},{"name":"./src/extensions/SideMenu/dragging.ts","size":4733,"chunks":["a1ee98a"]},{"name":"./src/extensions/SideMenu/SideMenuPlugin.ts","size":14087,"chunks":["a1ee98a"]},{"name":"./src/extensions/SuggestionMenu/SuggestionPlugin.ts","size":8104,"chunks":["a1ee98a"]},{"name":"./src/extensions/TableHandles/TableHandlesPlugin.ts","size":26718,"chunks":["a1ee98a"]},{"name":"./src/extensions/TextAlignment/TextAlignmentExtension.ts","size":976,"chunks":["a1ee98a"]},{"name":"./src/extensions/TextColor/TextColorExtension.ts","size":753,"chunks":["a1ee98a"]},{"name":"./src/extensions/TrailingNode/TrailingNodeExtension.ts","size":1563,"chunks":["a1ee98a"]},{"name":"./src/pm-nodes/BlockContainer.ts","size":2038,"chunks":["a1ee98a"]},{"name":"./src/pm-nodes/BlockGroup.ts","size":1102,"chunks":["a1ee98a"]},{"name":"./src/pm-nodes/Doc.ts","size":90,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteExtensions.ts","size":4928,"chunks":["a1ee98a"]},{"name":"./src/editor/transformPasted.ts","size":2604,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteTipTapEditor.ts","size":3938,"chunks":["a1ee98a"]},{"name":"./src/style.css","size":0,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteEditor.ts","size":31088,"chunks":["a1ee98a"]},{"name":"./src/editor/defaultColors.ts","size":1193,"chunks":["a1ee98a"]},{"name":"./src/exporter/Exporter.ts","size":1075,"chunks":["a1ee98a"]},{"name":"./src/exporter/mapping.ts","size":197,"chunks":["a1ee98a"]},{"name":"./src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts","size":1204,"chunks":["a1ee98a"]},{"name":"./src/util/combineByGroup.ts","size":550,"chunks":["a1ee98a"]},{"name":"./src/api/testUtil/partialBlockTestUtil.ts","size":3860,"chunks":["a1ee98a"]},{"name":"./src/index.ts","size":0,"chunks":["a1ee98a"]},{"name":"./src/comments/threadstore/ThreadStoreAuth.ts","size":25,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/DefaultThreadStoreAuth.ts","size":2014,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/ThreadStore.ts","size":77,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/TipTapThreadStore.ts","size":5321,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/yjsHelpers.ts","size":3002,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/YjsThreadStoreBase.ts","size":790,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/RESTYjsThreadStore.ts","size":2069,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/YjsThreadStore.ts","size":7267,"chunks":["1627b02"]},{"name":"./src/comments/index.ts","size":0,"chunks":["1627b02"]},{"name":"./src/i18n/locales/ar.ts","size":7904,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/de.ts","size":8626,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/es.ts","size":8483,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/fr.ts","size":9256,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/hr.ts","size":8518,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/is.ts","size":8246,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/it.ts","size":8582,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/ja.ts","size":7506,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/ko.ts","size":7283,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/nl.ts","size":8481,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/no.ts","size":8357,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/pl.ts","size":8172,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/pt.ts","size":8419,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/ru.ts","size":9103,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/uk.ts","size":9034,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/vi.ts","size":8281,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/zh.ts","size":7200,"chunks":["9eaffe2"]},{"name":"./src/i18n/index.ts","size":0,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/en.ts","size":8004,"chunks":["a1e239a"]}]}
|
|
1
|
+
{"builtAt":1744025813960,"assets":[{"name":"blocknote.cjs","size":180166},{"name":"comments.cjs","size":11826},{"name":"locales.cjs","size":111460},{"name":"en-D4taoCs4.cjs","size":5539},{"name":"en-D4taoCs4.cjs.map","size":12801},{"name":"comments.cjs.map","size":47589},{"name":"locales.cjs.map","size":233670},{"name":"blocknote.cjs.map","size":849985}],"chunks":[{"id":"a1ee98a","entry":true,"initial":true,"files":["blocknote.cjs"],"names":["blocknote"]},{"id":"1627b02","entry":true,"initial":true,"files":["comments.cjs"],"names":["comments"]},{"id":"9eaffe2","entry":true,"initial":true,"files":["locales.cjs"],"names":["locales"]},{"id":"a1e239a","entry":false,"initial":true,"files":["en-D4taoCs4.cjs"],"names":["en"]}],"modules":[{"name":"./src/util/typescript.ts","size":331,"chunks":["a1ee98a"]},{"name":"./src/api/getBlockInfoFromPos.ts","size":3648,"chunks":["a1ee98a"]},{"name":"./src/extensions/UniqueID/UniqueID.ts","size":9054,"chunks":["a1ee98a"]},{"name":"./src/schema/inlineContent/types.ts","size":302,"chunks":["a1ee98a"]},{"name":"./src/util/table.ts","size":1212,"chunks":["a1ee98a"]},{"name":"./src/util/browser.ts","size":536,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultBlockHelpers.ts","size":1755,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultProps.ts","size":269,"chunks":["a1ee98a"]},{"name":"./src/util/string.ts","size":299,"chunks":["a1ee98a"]},{"name":"./src/schema/blocks/internal.ts","size":4130,"chunks":["a1ee98a"]},{"name":"./src/schema/blocks/createSpec.ts","size":3609,"chunks":["a1ee98a"]},{"name":"./src/api/nodeConversions/nodeToBlock.ts","size":9521,"chunks":["a1ee98a"]},{"name":"./src/schema/inlineContent/internal.ts","size":1398,"chunks":["a1ee98a"]},{"name":"./src/schema/inlineContent/createSpec.ts","size":2739,"chunks":["a1ee98a"]},{"name":"./src/schema/styles/internal.ts","size":1162,"chunks":["a1ee98a"]},{"name":"./src/schema/styles/createSpec.ts","size":1263,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/tables/tables.ts","size":10346,"chunks":["a1ee98a"]},{"name":"./src/api/nodeConversions/blockToNode.ts","size":6874,"chunks":["a1ee98a"]},{"name":"./src/api/nodeUtil.ts","size":490,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/updateBlock/updateBlock.ts","size":4754,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/util/serializeBlocksExternalHTML.ts","size":5160,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/externalHTMLExporter.ts","size":886,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/util/serializeBlocksInternalHTML.ts","size":3264,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/html/internalHTMLSerializer.ts","size":288,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/parse/parseFigureElement.ts","size":342,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createAddFileButton.ts","size":1725,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createFileNameWithIcon.ts","size":753,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.ts","size":1428,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/toExternalHTML/createFigureWithCaption.ts","size":307,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/toExternalHTML/createLinkWithCaption.ts","size":294,"chunks":["a1ee98a"]},{"name":"./src/blocks/AudioBlockContent/parseAudioElement.ts","size":108,"chunks":["a1ee98a"]},{"name":"./src/blocks/AudioBlockContent/AudioBlockContent.ts","size":3155,"chunks":["a1ee98a"]},{"name":"./src/blocks/CodeBlockContent/CodeBlockContent.ts","size":9013,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/parse/parseEmbedElement.ts","size":108,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/FileBlockContent.ts","size":1460,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts","size":4637,"chunks":["a1ee98a"]},{"name":"./src/blocks/FileBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts","size":316,"chunks":["a1ee98a"]},{"name":"./src/blocks/ImageBlockContent/parseImageElement.ts","size":175,"chunks":["a1ee98a"]},{"name":"./src/blocks/ImageBlockContent/ImageBlockContent.ts","size":3243,"chunks":["a1ee98a"]},{"name":"./src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts","size":854,"chunks":["a1ee98a"]},{"name":"./src/extensions/BackgroundColor/BackgroundColorMark.ts","size":946,"chunks":["a1ee98a"]},{"name":"./src/extensions/TextColor/TextColorMark.ts","size":866,"chunks":["a1ee98a"]},{"name":"./src/blocks/HeadingBlockContent/HeadingBlockContent.ts","size":3418,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/splitBlock/splitBlock.ts","size":868,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.ts","size":1429,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts","size":3415,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts","size":7148,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts","size":2207,"chunks":["a1ee98a"]},{"name":"./src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts","size":4427,"chunks":["a1ee98a"]},{"name":"./src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts","size":1434,"chunks":["a1ee98a"]},{"name":"./src/blocks/QuoteBlockContent/QuoteBlockContent.ts","size":1927,"chunks":["a1ee98a"]},{"name":"./src/blocks/TableBlockContent/TableExtension.ts","size":2297,"chunks":["a1ee98a"]},{"name":"./src/blocks/TableBlockContent/TableBlockContent.ts","size":4708,"chunks":["a1ee98a"]},{"name":"./src/blocks/VideoBlockContent/parseVideoElement.ts","size":175,"chunks":["a1ee98a"]},{"name":"./src/blocks/VideoBlockContent/VideoBlockContent.ts","size":3162,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultBlocks.ts","size":1163,"chunks":["a1ee98a"]},{"name":"./src/blocks/defaultBlockTypeGuards.ts","size":1688,"chunks":["a1ee98a"]},{"name":"./src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts","size":7072,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteSchema.ts","size":1044,"chunks":["a1ee98a"]},{"name":"./src/blocks/PageBreakBlockContent/schema.ts","size":350,"chunks":["a1ee98a"]},{"name":"./src/blocks/PageBreakBlockContent/getPageBreakSlashMenuItems.ts","size":536,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts","size":1141,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/moveBlocks/moveBlocks.ts","size":5693,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/nestBlock/nestBlock.ts","size":2324,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts","size":2533,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/removeBlocks/removeBlocks.ts","size":123,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/getBlock/getBlock.ts","size":2452,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/insertContentAt.ts","size":1120,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/selections/selection.ts","size":4698,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/selections/textCursorPosition/textCursorPosition.ts","size":2880,"chunks":["a1ee98a"]},{"name":"./src/util/esmDependencies.ts","size":820,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/markdown/removeUnderlinesRehypePlugin.ts","size":752,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts","size":969,"chunks":["a1ee98a"]},{"name":"./src/api/exporters/markdown/markdownExporter.ts","size":837,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/html/util/nestedLists.ts","size":2174,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/html/parseHTML.ts","size":503,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/markdown/parseMarkdown.ts","size":1201,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/acceptedMIMETypes.ts","size":134,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/handleFileInsertion.ts","size":3917,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/fileDropExtension.ts","size":884,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/handleVSCodePaste.ts","size":661,"chunks":["a1ee98a"]},{"name":"./src/api/parsers/markdown/detectMarkdown.ts","size":1112,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/fromClipboard/pasteExtension.ts","size":2109,"chunks":["a1ee98a"]},{"name":"./src/api/nodeConversions/fragmentToBlocks.ts","size":859,"chunks":["a1ee98a"]},{"name":"./src/api/clipboard/toClipboard/copyExtension.ts","size":5228,"chunks":["a1ee98a"]},{"name":"./src/extensions/BackgroundColor/BackgroundColorExtension.ts","size":819,"chunks":["a1ee98a"]},{"name":"./src/extensions/Collaboration/createCollaborationExtensions.ts","size":3553,"chunks":["a1ee98a"]},{"name":"./src/extensions/Comments/CommentMark.ts","size":1428,"chunks":["a1ee98a"]},{"name":"./src/util/EventEmitter.ts","size":744,"chunks":["a1ee98a"]},{"name":"./src/extensions/Comments/userstore/UserStore.ts","size":1354,"chunks":["a1ee98a"]},{"name":"./src/extensions/Comments/CommentsPlugin.ts","size":7656,"chunks":["a1ee98a"]},{"name":"./src/extensions/FilePanel/FilePanelPlugin.ts","size":3584,"chunks":["a1ee98a"]},{"name":"./src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts","size":5323,"chunks":["a1ee98a"]},{"name":"./src/extensions/HardBreak/HardBreak.ts","size":376,"chunks":["a1ee98a"]},{"name":"./src/api/blockManipulation/commands/mergeBlocks/mergeBlocks.ts","size":3228,"chunks":["a1ee98a"]},{"name":"./src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts","size":18010,"chunks":["a1ee98a"]},{"name":"./src/extensions/LinkToolbar/LinkToolbarPlugin.ts","size":7611,"chunks":["a1ee98a"]},{"name":"./src/extensions/LinkToolbar/protocols.ts","size":172,"chunks":["a1ee98a"]},{"name":"./src/extensions/NodeSelectionKeyboard/NodeSelectionKeyboardPlugin.ts","size":1195,"chunks":["a1ee98a"]},{"name":"./src/extensions/Placeholder/PlaceholderPlugin.ts","size":3609,"chunks":["a1ee98a"]},{"name":"./src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts","size":4826,"chunks":["a1ee98a"]},{"name":"./src/extensions/ShowSelection/ShowSelectionPlugin.ts","size":967,"chunks":["a1ee98a"]},{"name":"./src/extensions/getDraggableBlockFromElement.ts","size":404,"chunks":["a1ee98a"]},{"name":"./src/extensions/SideMenu/MultipleNodeSelection.ts","size":1616,"chunks":["a1ee98a"]},{"name":"./src/extensions/SideMenu/dragging.ts","size":4733,"chunks":["a1ee98a"]},{"name":"./src/extensions/SideMenu/SideMenuPlugin.ts","size":14087,"chunks":["a1ee98a"]},{"name":"./src/api/positionMapping.ts","size":1638,"chunks":["a1ee98a"]},{"name":"./src/extensions/SuggestionMenu/SuggestionPlugin.ts","size":8635,"chunks":["a1ee98a"]},{"name":"./src/extensions/TableHandles/TableHandlesPlugin.ts","size":26718,"chunks":["a1ee98a"]},{"name":"./src/extensions/TextAlignment/TextAlignmentExtension.ts","size":976,"chunks":["a1ee98a"]},{"name":"./src/extensions/TextColor/TextColorExtension.ts","size":753,"chunks":["a1ee98a"]},{"name":"./src/extensions/TrailingNode/TrailingNodeExtension.ts","size":1563,"chunks":["a1ee98a"]},{"name":"./src/pm-nodes/BlockContainer.ts","size":2038,"chunks":["a1ee98a"]},{"name":"./src/pm-nodes/BlockGroup.ts","size":1102,"chunks":["a1ee98a"]},{"name":"./src/pm-nodes/Doc.ts","size":90,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteExtensions.ts","size":4928,"chunks":["a1ee98a"]},{"name":"./src/editor/transformPasted.ts","size":2604,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteTipTapEditor.ts","size":3938,"chunks":["a1ee98a"]},{"name":"./src/style.css","size":0,"chunks":["a1ee98a"]},{"name":"./src/editor/BlockNoteEditor.ts","size":31088,"chunks":["a1ee98a"]},{"name":"./src/editor/defaultColors.ts","size":1193,"chunks":["a1ee98a"]},{"name":"./src/exporter/Exporter.ts","size":1075,"chunks":["a1ee98a"]},{"name":"./src/exporter/mapping.ts","size":197,"chunks":["a1ee98a"]},{"name":"./src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts","size":1204,"chunks":["a1ee98a"]},{"name":"./src/util/combineByGroup.ts","size":550,"chunks":["a1ee98a"]},{"name":"./src/api/testUtil/partialBlockTestUtil.ts","size":3860,"chunks":["a1ee98a"]},{"name":"./src/index.ts","size":0,"chunks":["a1ee98a"]},{"name":"./src/comments/threadstore/ThreadStoreAuth.ts","size":25,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/DefaultThreadStoreAuth.ts","size":2014,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/ThreadStore.ts","size":77,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/TipTapThreadStore.ts","size":5321,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/yjsHelpers.ts","size":3002,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/YjsThreadStoreBase.ts","size":790,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/RESTYjsThreadStore.ts","size":2069,"chunks":["1627b02"]},{"name":"./src/comments/threadstore/yjs/YjsThreadStore.ts","size":7267,"chunks":["1627b02"]},{"name":"./src/comments/index.ts","size":0,"chunks":["1627b02"]},{"name":"./src/i18n/locales/ar.ts","size":7904,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/de.ts","size":8624,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/es.ts","size":8483,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/fr.ts","size":9256,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/hr.ts","size":8518,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/is.ts","size":8246,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/it.ts","size":8582,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/ja.ts","size":7506,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/ko.ts","size":7283,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/nl.ts","size":8481,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/no.ts","size":8357,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/pl.ts","size":8172,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/pt.ts","size":8419,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/ru.ts","size":9103,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/uk.ts","size":9034,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/vi.ts","size":8281,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/zh.ts","size":7200,"chunks":["9eaffe2"]},{"name":"./src/i18n/index.ts","size":0,"chunks":["9eaffe2"]},{"name":"./src/i18n/locales/en.ts","size":8004,"chunks":["a1e239a"]}]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as Y from "yjs";
|
|
3
|
+
import { BlockNoteEditor } from "../editor/BlockNoteEditor.js";
|
|
4
|
+
import { trackPosition } from "./positionMapping.js";
|
|
5
|
+
|
|
6
|
+
describe("PositionStorage with local editor", () => {
|
|
7
|
+
let editor: BlockNoteEditor;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
editor = BlockNoteEditor.create();
|
|
11
|
+
editor.mount(document.createElement("div"));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
editor.mount(undefined);
|
|
16
|
+
editor._tiptapEditor.destroy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("mount and unmount", () => {
|
|
20
|
+
it("should register transaction handler on creation", () => {
|
|
21
|
+
editor._tiptapEditor.on = vi.fn();
|
|
22
|
+
trackPosition(editor, 0);
|
|
23
|
+
|
|
24
|
+
expect(editor._tiptapEditor.on).toHaveBeenCalledWith(
|
|
25
|
+
"transaction",
|
|
26
|
+
expect.any(Function)
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("set and get positions", () => {
|
|
32
|
+
it("should store and retrieve positions without Y.js", () => {
|
|
33
|
+
const getPos = trackPosition(editor, 10);
|
|
34
|
+
|
|
35
|
+
expect(getPos()).toBe(10);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should handle right side positions", () => {
|
|
39
|
+
const getPos = trackPosition(editor, 10, "right");
|
|
40
|
+
|
|
41
|
+
expect(getPos()).toBe(10);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should update mapping for local transactions before the position", () => {
|
|
46
|
+
// Set initial content
|
|
47
|
+
editor.insertBlocks(
|
|
48
|
+
[
|
|
49
|
+
{
|
|
50
|
+
id: "1",
|
|
51
|
+
type: "paragraph",
|
|
52
|
+
content: [
|
|
53
|
+
{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: "Hello World",
|
|
56
|
+
styles: {},
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
editor.document[0],
|
|
62
|
+
"before"
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Start tracking
|
|
66
|
+
const getPos = trackPosition(editor, 10);
|
|
67
|
+
|
|
68
|
+
// Move the cursor to the start of the document
|
|
69
|
+
editor.setTextCursorPosition(editor.document[0], "start");
|
|
70
|
+
|
|
71
|
+
// Insert text at the start of the document
|
|
72
|
+
editor.insertInlineContent([
|
|
73
|
+
{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: "Test",
|
|
76
|
+
styles: {},
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
// Position should be updated according to mapping
|
|
81
|
+
expect(getPos()).toBe(14);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should not update mapping for local transactions after the position", () => {
|
|
85
|
+
// Set initial content
|
|
86
|
+
editor.insertBlocks(
|
|
87
|
+
[
|
|
88
|
+
{
|
|
89
|
+
id: "1",
|
|
90
|
+
type: "paragraph",
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: "Hello World",
|
|
95
|
+
styles: {},
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
editor.document[0],
|
|
101
|
+
"before"
|
|
102
|
+
);
|
|
103
|
+
// Start tracking
|
|
104
|
+
const getPos = trackPosition(editor, 10);
|
|
105
|
+
|
|
106
|
+
// Move the cursor to the end of the document
|
|
107
|
+
editor.setTextCursorPosition(editor.document[0], "end");
|
|
108
|
+
|
|
109
|
+
// Insert text at the end of the document
|
|
110
|
+
editor.insertInlineContent([
|
|
111
|
+
{
|
|
112
|
+
type: "text",
|
|
113
|
+
text: "Test",
|
|
114
|
+
styles: {},
|
|
115
|
+
},
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
// Position should not be updated
|
|
119
|
+
expect(getPos()).toBe(10);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should track positions on each side", () => {
|
|
123
|
+
editor.replaceBlocks(editor.document, [
|
|
124
|
+
{
|
|
125
|
+
type: "paragraph",
|
|
126
|
+
content: "Hello World",
|
|
127
|
+
},
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
// Store position at "Hello| World"
|
|
131
|
+
const getCursorPos = trackPosition(editor, 6);
|
|
132
|
+
const getStartPos = trackPosition(editor, 3);
|
|
133
|
+
const getStartRightPos = trackPosition(editor, 3, "right");
|
|
134
|
+
const getPosAfterPos = trackPosition(editor, 4);
|
|
135
|
+
const getPosAfterRightPos = trackPosition(editor, 4, "right");
|
|
136
|
+
// Insert text at the beginning
|
|
137
|
+
editor._tiptapEditor.commands.insertContentAt(3, "Test ");
|
|
138
|
+
|
|
139
|
+
// Position should be updated
|
|
140
|
+
expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
|
|
141
|
+
expect(getStartPos()).toBe(3); // 3
|
|
142
|
+
expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
|
|
143
|
+
expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
144
|
+
expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should handle multiple transactions", () => {
|
|
148
|
+
editor.replaceBlocks(editor.document, [
|
|
149
|
+
{
|
|
150
|
+
type: "paragraph",
|
|
151
|
+
content: "Hello World",
|
|
152
|
+
},
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
// Store position at "Hello| World"
|
|
156
|
+
const getCursorPos = trackPosition(editor, 6);
|
|
157
|
+
const getStartPos = trackPosition(editor, 3);
|
|
158
|
+
const getStartRightPos = trackPosition(editor, 3, "right");
|
|
159
|
+
const getPosAfterPos = trackPosition(editor, 4);
|
|
160
|
+
const getPosAfterRightPos = trackPosition(editor, 4, "right");
|
|
161
|
+
|
|
162
|
+
// Insert text at the beginning
|
|
163
|
+
editor._tiptapEditor.commands.insertContentAt(3, "T");
|
|
164
|
+
editor._tiptapEditor.commands.insertContentAt(4, "e");
|
|
165
|
+
editor._tiptapEditor.commands.insertContentAt(5, "s");
|
|
166
|
+
editor._tiptapEditor.commands.insertContentAt(6, "t");
|
|
167
|
+
editor._tiptapEditor.commands.insertContentAt(7, " ");
|
|
168
|
+
|
|
169
|
+
// Position should be updated
|
|
170
|
+
expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
|
|
171
|
+
expect(getStartPos()).toBe(3); // 3
|
|
172
|
+
expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
|
|
173
|
+
expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
174
|
+
expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("PositionStorage with remote editor", () => {
|
|
179
|
+
// Function to sync two documents
|
|
180
|
+
function syncDocs(sourceDoc: Y.Doc, targetDoc: Y.Doc) {
|
|
181
|
+
// Create update message from source
|
|
182
|
+
const update = Y.encodeStateAsUpdate(sourceDoc);
|
|
183
|
+
|
|
184
|
+
// Apply update to target
|
|
185
|
+
Y.applyUpdate(targetDoc, update);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Set up two-way sync
|
|
189
|
+
function setupTwoWaySync(doc1: Y.Doc, doc2: Y.Doc) {
|
|
190
|
+
// Sync initial states
|
|
191
|
+
syncDocs(doc1, doc2);
|
|
192
|
+
syncDocs(doc2, doc1);
|
|
193
|
+
|
|
194
|
+
// Set up observers for future changes
|
|
195
|
+
doc1.on("update", (update: Uint8Array) => {
|
|
196
|
+
Y.applyUpdate(doc2, update);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
doc2.on("update", (update: Uint8Array) => {
|
|
200
|
+
Y.applyUpdate(doc1, update);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
describe("remote editor", () => {
|
|
205
|
+
let localEditor: BlockNoteEditor;
|
|
206
|
+
let remoteEditor: BlockNoteEditor;
|
|
207
|
+
let ydoc: Y.Doc;
|
|
208
|
+
let remoteYdoc: Y.Doc;
|
|
209
|
+
|
|
210
|
+
beforeEach(() => {
|
|
211
|
+
ydoc = new Y.Doc();
|
|
212
|
+
remoteYdoc = new Y.Doc();
|
|
213
|
+
// Create a mock editor
|
|
214
|
+
localEditor = BlockNoteEditor.create({
|
|
215
|
+
collaboration: {
|
|
216
|
+
fragment: ydoc.getXmlFragment("doc"),
|
|
217
|
+
user: { color: "#ff0000", name: "Local User" },
|
|
218
|
+
provider: undefined,
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
const div = document.createElement("div");
|
|
222
|
+
localEditor.mount(div);
|
|
223
|
+
|
|
224
|
+
remoteEditor = BlockNoteEditor.create({
|
|
225
|
+
collaboration: {
|
|
226
|
+
fragment: remoteYdoc.getXmlFragment("doc"),
|
|
227
|
+
user: { color: "#ff0000", name: "Remote User" },
|
|
228
|
+
provider: undefined,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const remoteDiv = document.createElement("div");
|
|
233
|
+
remoteEditor.mount(remoteDiv);
|
|
234
|
+
setupTwoWaySync(ydoc, remoteYdoc);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
afterEach(() => {
|
|
238
|
+
ydoc.destroy();
|
|
239
|
+
remoteYdoc.destroy();
|
|
240
|
+
localEditor.mount(undefined);
|
|
241
|
+
localEditor._tiptapEditor.destroy();
|
|
242
|
+
remoteEditor.mount(undefined);
|
|
243
|
+
remoteEditor._tiptapEditor.destroy();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should update the local position when collaborating", () => {
|
|
247
|
+
localEditor.replaceBlocks(localEditor.document, [
|
|
248
|
+
{
|
|
249
|
+
type: "paragraph",
|
|
250
|
+
content: "Hello World",
|
|
251
|
+
},
|
|
252
|
+
]);
|
|
253
|
+
|
|
254
|
+
// Store position at "Hello| World"
|
|
255
|
+
const getCursorPos = trackPosition(localEditor, 6);
|
|
256
|
+
// Store position at "|Hello World"
|
|
257
|
+
const getStartPos = trackPosition(localEditor, 3);
|
|
258
|
+
// Store position at "|Hello World" (but on the right side)
|
|
259
|
+
const getStartRightPos = trackPosition(localEditor, 3, "right");
|
|
260
|
+
// Store position at "H|ello World"
|
|
261
|
+
const getPosAfterPos = trackPosition(localEditor, 4);
|
|
262
|
+
// Store position at "H|ello World" (but on the right side)
|
|
263
|
+
const getPosAfterRightPos = trackPosition(localEditor, 4, "right");
|
|
264
|
+
|
|
265
|
+
// Insert text at the beginning
|
|
266
|
+
localEditor._tiptapEditor.commands.insertContentAt(3, "Test ");
|
|
267
|
+
|
|
268
|
+
// Position should be updated
|
|
269
|
+
expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
|
|
270
|
+
expect(getStartPos()).toBe(3); // 3
|
|
271
|
+
expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
|
|
272
|
+
expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
273
|
+
expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("should handle multiple transactions when collaborating", () => {
|
|
277
|
+
localEditor.replaceBlocks(localEditor.document, [
|
|
278
|
+
{
|
|
279
|
+
type: "paragraph",
|
|
280
|
+
content: "Hello World",
|
|
281
|
+
},
|
|
282
|
+
]);
|
|
283
|
+
|
|
284
|
+
// Store position at "Hello| World"
|
|
285
|
+
const getCursorPos = trackPosition(localEditor, 6);
|
|
286
|
+
// Store position at "|Hello World"
|
|
287
|
+
const getStartPos = trackPosition(localEditor, 3);
|
|
288
|
+
// Store position at "|Hello World" (but on the right side)
|
|
289
|
+
const getStartRightPos = trackPosition(localEditor, 3, "right");
|
|
290
|
+
// Store position at "H|ello World"
|
|
291
|
+
const getPosAfterPos = trackPosition(localEditor, 4);
|
|
292
|
+
// Store position at "H|ello World" (but on the right side)
|
|
293
|
+
const getPosAfterRightPos = trackPosition(localEditor, 4, "right");
|
|
294
|
+
|
|
295
|
+
// Insert text at the beginning
|
|
296
|
+
localEditor._tiptapEditor.commands.insertContentAt(3, "T");
|
|
297
|
+
localEditor._tiptapEditor.commands.insertContentAt(4, "e");
|
|
298
|
+
localEditor._tiptapEditor.commands.insertContentAt(5, "s");
|
|
299
|
+
localEditor._tiptapEditor.commands.insertContentAt(6, "t");
|
|
300
|
+
localEditor._tiptapEditor.commands.insertContentAt(7, " ");
|
|
301
|
+
|
|
302
|
+
// Position should be updated
|
|
303
|
+
expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
|
|
304
|
+
expect(getStartPos()).toBe(3); // 3
|
|
305
|
+
expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
|
|
306
|
+
expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
307
|
+
expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("should update the local position from a remote transaction", () => {
|
|
311
|
+
remoteEditor.replaceBlocks(remoteEditor.document, [
|
|
312
|
+
{
|
|
313
|
+
type: "paragraph",
|
|
314
|
+
content: "Hello World",
|
|
315
|
+
},
|
|
316
|
+
]);
|
|
317
|
+
|
|
318
|
+
// Store position at "Hello| World"
|
|
319
|
+
const getCursorPos = trackPosition(localEditor, 6);
|
|
320
|
+
// Store position at "|Hello World"
|
|
321
|
+
const getStartPos = trackPosition(localEditor, 3);
|
|
322
|
+
// Store position at "|Hello World" (but on the right side)
|
|
323
|
+
const getStartRightPos = trackPosition(localEditor, 3, "right");
|
|
324
|
+
// Store position at "H|ello World"
|
|
325
|
+
const getPosAfterPos = trackPosition(localEditor, 4);
|
|
326
|
+
// Store position at "H|ello World" (but on the right side)
|
|
327
|
+
const getPosAfterRightPos = trackPosition(localEditor, 4, "right");
|
|
328
|
+
|
|
329
|
+
// Insert text at the beginning
|
|
330
|
+
localEditor._tiptapEditor.commands.insertContentAt(3, "Test ");
|
|
331
|
+
|
|
332
|
+
// Position should be updated
|
|
333
|
+
expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
|
|
334
|
+
expect(getStartPos()).toBe(3); // 3
|
|
335
|
+
expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
|
|
336
|
+
expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
337
|
+
expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it("should update the remote position from a remote transaction", () => {
|
|
341
|
+
remoteEditor.replaceBlocks(remoteEditor.document, [
|
|
342
|
+
{
|
|
343
|
+
type: "paragraph",
|
|
344
|
+
content: "Hello World",
|
|
345
|
+
},
|
|
346
|
+
]);
|
|
347
|
+
|
|
348
|
+
// Store position at "Hello| World"
|
|
349
|
+
const getCursorPos = trackPosition(remoteEditor, 6);
|
|
350
|
+
// Store position at "|Hello World"
|
|
351
|
+
const getStartPos = trackPosition(remoteEditor, 3);
|
|
352
|
+
// Store position at "|Hello World" (but on the right side)
|
|
353
|
+
const getStartRightPos = trackPosition(remoteEditor, 3, "right");
|
|
354
|
+
// Store position at "H|ello World"
|
|
355
|
+
const getPosAfterPos = trackPosition(remoteEditor, 4);
|
|
356
|
+
// Store position at "H|ello World" (but on the right side)
|
|
357
|
+
const getPosAfterRightPos = trackPosition(remoteEditor, 4, "right");
|
|
358
|
+
|
|
359
|
+
// Insert text at the beginning
|
|
360
|
+
localEditor._tiptapEditor.commands.insertContentAt(3, "Test ");
|
|
361
|
+
|
|
362
|
+
// Position should be updated
|
|
363
|
+
expect(getCursorPos()).toBe(11); // 6 + 5 ("Test " length)
|
|
364
|
+
expect(getStartPos()).toBe(3); // 3
|
|
365
|
+
expect(getStartRightPos()).toBe(8); // 3 + 5 ("Test " length)
|
|
366
|
+
expect(getPosAfterPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
367
|
+
expect(getPosAfterRightPos()).toBe(9); // 4 + 5 ("Test " length)
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Mapping } from "prosemirror-transform";
|
|
2
|
+
import {
|
|
3
|
+
absolutePositionToRelativePosition,
|
|
4
|
+
relativePositionToAbsolutePosition,
|
|
5
|
+
ySyncPluginKey,
|
|
6
|
+
} from "y-prosemirror";
|
|
7
|
+
import type { BlockNoteEditor } from "../editor/BlockNoteEditor.js";
|
|
8
|
+
import * as Y from "yjs";
|
|
9
|
+
import type { ProsemirrorBinding } from "y-prosemirror";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This is used to track a mapping for each editor. The mapping stores the mappings for each transaction since the first transaction that was tracked.
|
|
13
|
+
*/
|
|
14
|
+
const editorToMapping = new Map<BlockNoteEditor<any, any, any>, Mapping>();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* This initializes a single mapping for an editor instance.
|
|
18
|
+
*/
|
|
19
|
+
function getMapping(editor: BlockNoteEditor<any, any, any>) {
|
|
20
|
+
if (editorToMapping.has(editor)) {
|
|
21
|
+
// Mapping already initialized, so we don't need to do anything
|
|
22
|
+
return editorToMapping.get(editor)!;
|
|
23
|
+
}
|
|
24
|
+
const mapping = new Mapping();
|
|
25
|
+
editor._tiptapEditor.on("transaction", ({ transaction }) => {
|
|
26
|
+
mapping.appendMapping(transaction.mapping);
|
|
27
|
+
});
|
|
28
|
+
editor._tiptapEditor.on("destroy", () => {
|
|
29
|
+
// Cleanup the mapping when the editor is destroyed
|
|
30
|
+
editorToMapping.delete(editor);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// There only is one mapping per editor, so we can just set it
|
|
34
|
+
editorToMapping.set(editor, mapping);
|
|
35
|
+
|
|
36
|
+
return mapping;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* This is used to keep track of positions of elements in the editor.
|
|
41
|
+
* It is needed because y-prosemirror's sync plugin can disrupt normal prosemirror position mapping.
|
|
42
|
+
*
|
|
43
|
+
* It is specifically made to be able to be used whether the editor is being used in a collaboratively, or single user, providing the same API.
|
|
44
|
+
*
|
|
45
|
+
* @param editor The editor to track the position of.
|
|
46
|
+
* @param position The position to track.
|
|
47
|
+
* @param side The side of the position to track. "left" is the default. "right" would move with the change if the change is in the right direction.
|
|
48
|
+
* @returns A function that returns the position of the element.
|
|
49
|
+
*/
|
|
50
|
+
export function trackPosition(
|
|
51
|
+
/**
|
|
52
|
+
* The editor to track the position of.
|
|
53
|
+
*/
|
|
54
|
+
editor: BlockNoteEditor<any, any, any>,
|
|
55
|
+
/**
|
|
56
|
+
* The position to track.
|
|
57
|
+
*/
|
|
58
|
+
position: number,
|
|
59
|
+
/**
|
|
60
|
+
* This is the side of the position to track. "left" is the default. "right" would move with the change if the change is in the right direction.
|
|
61
|
+
*/
|
|
62
|
+
side: "left" | "right" = "left"
|
|
63
|
+
): () => number {
|
|
64
|
+
const ySyncPluginState = ySyncPluginKey.getState(editor.prosemirrorState) as {
|
|
65
|
+
doc: Y.Doc;
|
|
66
|
+
binding: ProsemirrorBinding;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
if (!ySyncPluginState) {
|
|
70
|
+
// No y-prosemirror sync plugin, so we need to track the mapping manually
|
|
71
|
+
// This will initialize the mapping for this editor, if needed
|
|
72
|
+
const mapping = getMapping(editor);
|
|
73
|
+
|
|
74
|
+
// This is the start point of tracking the mapping
|
|
75
|
+
const trackedMapLength = mapping.maps.length;
|
|
76
|
+
|
|
77
|
+
return () => {
|
|
78
|
+
const pos = mapping
|
|
79
|
+
// Only read the history of the mapping that we care about
|
|
80
|
+
.slice(trackedMapLength)
|
|
81
|
+
.map(position, side === "left" ? -1 : 1);
|
|
82
|
+
|
|
83
|
+
return pos;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const relativePosition = absolutePositionToRelativePosition(
|
|
88
|
+
// Track the position after the position if we are on the right side
|
|
89
|
+
position + (side === "right" ? 1 : 0),
|
|
90
|
+
ySyncPluginState.binding.type,
|
|
91
|
+
ySyncPluginState.binding.mapping
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return () => {
|
|
95
|
+
const curYSyncPluginState = ySyncPluginKey.getState(
|
|
96
|
+
editor.prosemirrorState
|
|
97
|
+
) as typeof ySyncPluginState;
|
|
98
|
+
const pos = relativePositionToAbsolutePosition(
|
|
99
|
+
curYSyncPluginState.doc,
|
|
100
|
+
curYSyncPluginState.binding.type,
|
|
101
|
+
relativePosition,
|
|
102
|
+
curYSyncPluginState.binding.mapping
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// This can happen if the element is garbage collected
|
|
106
|
+
if (pos === null) {
|
|
107
|
+
throw new Error("Position not found, cannot track positions");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return pos + (side === "right" ? -1 : 0);
|
|
111
|
+
};
|
|
112
|
+
}
|