@blocknote/core 0.1.0-alpha.3

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.
Files changed (143) hide show
  1. package/README.md +99 -0
  2. package/dist/blocknote.js +4485 -0
  3. package/dist/blocknote.js.map +1 -0
  4. package/dist/blocknote.umd.cjs +90 -0
  5. package/dist/blocknote.umd.cjs.map +1 -0
  6. package/dist/style.css +1 -0
  7. package/package.json +109 -0
  8. package/src/BlockNoteExtensions.ts +90 -0
  9. package/src/EditorContent.tsx +1 -0
  10. package/src/assets/inter-v12-latin/inter-v12-latin-100.woff +0 -0
  11. package/src/assets/inter-v12-latin/inter-v12-latin-100.woff2 +0 -0
  12. package/src/assets/inter-v12-latin/inter-v12-latin-200.woff +0 -0
  13. package/src/assets/inter-v12-latin/inter-v12-latin-200.woff2 +0 -0
  14. package/src/assets/inter-v12-latin/inter-v12-latin-300.woff +0 -0
  15. package/src/assets/inter-v12-latin/inter-v12-latin-300.woff2 +0 -0
  16. package/src/assets/inter-v12-latin/inter-v12-latin-500.woff +0 -0
  17. package/src/assets/inter-v12-latin/inter-v12-latin-500.woff2 +0 -0
  18. package/src/assets/inter-v12-latin/inter-v12-latin-600.woff +0 -0
  19. package/src/assets/inter-v12-latin/inter-v12-latin-600.woff2 +0 -0
  20. package/src/assets/inter-v12-latin/inter-v12-latin-700.woff +0 -0
  21. package/src/assets/inter-v12-latin/inter-v12-latin-700.woff2 +0 -0
  22. package/src/assets/inter-v12-latin/inter-v12-latin-800.woff +0 -0
  23. package/src/assets/inter-v12-latin/inter-v12-latin-800.woff2 +0 -0
  24. package/src/assets/inter-v12-latin/inter-v12-latin-900.woff +0 -0
  25. package/src/assets/inter-v12-latin/inter-v12-latin-900.woff2 +0 -0
  26. package/src/assets/inter-v12-latin/inter-v12-latin-regular.woff +0 -0
  27. package/src/assets/inter-v12-latin/inter-v12-latin-regular.woff2 +0 -0
  28. package/src/editor.module.css +3 -0
  29. package/src/extensions/Blocks/OrderedListPlugin.ts +46 -0
  30. package/src/extensions/Blocks/PreviousBlockTypePlugin.ts +146 -0
  31. package/src/extensions/Blocks/commands/joinBackward.ts +274 -0
  32. package/src/extensions/Blocks/helpers/findBlock.ts +3 -0
  33. package/src/extensions/Blocks/helpers/setBlockHeading.ts +30 -0
  34. package/src/extensions/Blocks/index.ts +15 -0
  35. package/src/extensions/Blocks/nodes/Block.module.css +226 -0
  36. package/src/extensions/Blocks/nodes/Block.ts +390 -0
  37. package/src/extensions/Blocks/nodes/BlockGroup.ts +28 -0
  38. package/src/extensions/Blocks/nodes/Content.ts +50 -0
  39. package/src/extensions/Blocks/nodes/README.md +26 -0
  40. package/src/extensions/Blocks/rule.ts +48 -0
  41. package/src/extensions/BubbleMenu/BubbleMenuExtension.tsx +28 -0
  42. package/src/extensions/BubbleMenu/BubbleMenuPlugin.ts +245 -0
  43. package/src/extensions/BubbleMenu/component/BubbleMenu.tsx +216 -0
  44. package/src/extensions/BubbleMenu/component/DropdownBlockItem.module.css +13 -0
  45. package/src/extensions/BubbleMenu/component/DropdownBlockItem.tsx +25 -0
  46. package/src/extensions/BubbleMenu/component/LinkToolbarButton.tsx +67 -0
  47. package/src/extensions/DraggableBlocks/DraggableBlocksExtension.ts +15 -0
  48. package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.tsx +266 -0
  49. package/src/extensions/DraggableBlocks/components/DragHandle.module.css +33 -0
  50. package/src/extensions/DraggableBlocks/components/DragHandle.tsx +108 -0
  51. package/src/extensions/DraggableBlocks/components/DragHandleMenu.module.css +10 -0
  52. package/src/extensions/DraggableBlocks/components/DragHandleMenu.tsx +18 -0
  53. package/src/extensions/Hyperlinks/HyperlinkMark.tsx +16 -0
  54. package/src/extensions/Hyperlinks/HyperlinkMenuPlugin.tsx +200 -0
  55. package/src/extensions/Hyperlinks/menus/HyperlinkBasicMenu.tsx +59 -0
  56. package/src/extensions/Hyperlinks/menus/HyperlinkEditMenu.tsx +72 -0
  57. package/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInput.tsx +173 -0
  58. package/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInputStyles.ts +36 -0
  59. package/src/extensions/Hyperlinks/menus/atlaskit/README.md +1 -0
  60. package/src/extensions/Hyperlinks/menus/atlaskit/ToolbarComponent.tsx +61 -0
  61. package/src/extensions/Paragraph/FixedParagraph.ts +12 -0
  62. package/src/extensions/Placeholder/PlaceholderExtension.ts +127 -0
  63. package/src/extensions/SlashMenu/SlashMenuExtension.ts +43 -0
  64. package/src/extensions/SlashMenu/SlashMenuItem.ts +56 -0
  65. package/src/extensions/SlashMenu/defaultCommands.tsx +229 -0
  66. package/src/extensions/SlashMenu/index.ts +11 -0
  67. package/src/extensions/TrailingNode/TrailingNodeExtension.ts +70 -0
  68. package/src/extensions/UniqueID/UniqueID.ts +281 -0
  69. package/src/extensions/helpers/formatKeyboardShortcut.ts +9 -0
  70. package/src/fonts-inter.css +94 -0
  71. package/src/globals.css +28 -0
  72. package/src/index.ts +5 -0
  73. package/src/lib/atlaskit/browser.ts +47 -0
  74. package/src/root.module.css +19 -0
  75. package/src/shared/components/toolbar/SimpleToolbarButton.module.css +13 -0
  76. package/src/shared/components/toolbar/SimpleToolbarButton.tsx +56 -0
  77. package/src/shared/components/toolbar/Toolbar.module.css +10 -0
  78. package/src/shared/components/toolbar/Toolbar.tsx +5 -0
  79. package/src/shared/components/toolbar/ToolbarSeparator.module.css +13 -0
  80. package/src/shared/components/toolbar/ToolbarSeparator.tsx +7 -0
  81. package/src/shared/components/tooltip/TooltipContent.module.css +15 -0
  82. package/src/shared/components/tooltip/TooltipContent.tsx +23 -0
  83. package/src/shared/hooks/useEditorForceUpdate.tsx +30 -0
  84. package/src/shared/plugins/suggestion/SuggestionItem.ts +31 -0
  85. package/src/shared/plugins/suggestion/SuggestionListReactRenderer.ts +227 -0
  86. package/src/shared/plugins/suggestion/SuggestionPlugin.ts +365 -0
  87. package/src/shared/plugins/suggestion/components/SuggestionGroup.module.css +45 -0
  88. package/src/shared/plugins/suggestion/components/SuggestionGroup.tsx +134 -0
  89. package/src/shared/plugins/suggestion/components/SuggestionList.module.css +10 -0
  90. package/src/shared/plugins/suggestion/components/SuggestionList.tsx +91 -0
  91. package/src/style.css +7 -0
  92. package/src/useEditor.ts +47 -0
  93. package/src/vite-env.d.ts +1 -0
  94. package/types/src/BlockNoteExtensions.d.ts +4 -0
  95. package/types/src/EditorContent.d.ts +1 -0
  96. package/types/src/extensions/Blocks/OrderedListPlugin.d.ts +2 -0
  97. package/types/src/extensions/Blocks/PreviousBlockTypePlugin.d.ts +13 -0
  98. package/types/src/extensions/Blocks/commands/joinBackward.d.ts +14 -0
  99. package/types/src/extensions/Blocks/helpers/findBlock.d.ts +6 -0
  100. package/types/src/extensions/Blocks/helpers/setBlockHeading.d.ts +5 -0
  101. package/types/src/extensions/Blocks/index.d.ts +1 -0
  102. package/types/src/extensions/Blocks/nodes/Block.d.ts +32 -0
  103. package/types/src/extensions/Blocks/nodes/BlockGroup.d.ts +2 -0
  104. package/types/src/extensions/Blocks/nodes/Content.d.ts +5 -0
  105. package/types/src/extensions/Blocks/rule.d.ts +16 -0
  106. package/types/src/extensions/BubbleMenu/BubbleMenuExtension.d.ts +5 -0
  107. package/types/src/extensions/BubbleMenu/BubbleMenuPlugin.d.ts +46 -0
  108. package/types/src/extensions/BubbleMenu/component/BubbleMenu.d.ts +5 -0
  109. package/types/src/extensions/BubbleMenu/component/DropdownBlockItem.d.ts +10 -0
  110. package/types/src/extensions/BubbleMenu/component/LinkToolbarButton.d.ts +11 -0
  111. package/types/src/extensions/DraggableBlocks/DraggableBlocksExtension.d.ts +7 -0
  112. package/types/src/extensions/DraggableBlocks/DraggableBlocksPlugin.d.ts +18 -0
  113. package/types/src/extensions/DraggableBlocks/components/DragHandle.d.ts +12 -0
  114. package/types/src/extensions/DraggableBlocks/components/DragHandleMenu.d.ts +6 -0
  115. package/types/src/extensions/Hyperlinks/HyperlinkMark.d.ts +7 -0
  116. package/types/src/extensions/Hyperlinks/HyperlinkMenuPlugin.d.ts +2 -0
  117. package/types/src/extensions/Hyperlinks/menus/HyperlinkBasicMenu.d.ts +12 -0
  118. package/types/src/extensions/Hyperlinks/menus/HyperlinkEditMenu.d.ts +10 -0
  119. package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInput.d.ts +39 -0
  120. package/types/src/extensions/Hyperlinks/menus/atlaskit/PanelTextInputStyles.d.ts +1 -0
  121. package/types/src/extensions/Hyperlinks/menus/atlaskit/ToolbarComponent.d.ts +11 -0
  122. package/types/src/extensions/Paragraph/FixedParagraph.d.ts +1 -0
  123. package/types/src/extensions/Placeholder/PlaceholderExtension.d.ts +25 -0
  124. package/types/src/extensions/SlashMenu/SlashMenuExtension.d.ts +10 -0
  125. package/types/src/extensions/SlashMenu/SlashMenuItem.d.ts +43 -0
  126. package/types/src/extensions/SlashMenu/defaultCommands.d.ts +8 -0
  127. package/types/src/extensions/SlashMenu/index.d.ts +5 -0
  128. package/types/src/extensions/TrailingNode/TrailingNodeExtension.d.ts +10 -0
  129. package/types/src/extensions/UniqueID/UniqueID.d.ts +3 -0
  130. package/types/src/extensions/helpers/formatKeyboardShortcut.d.ts +1 -0
  131. package/types/src/index.d.ts +4 -0
  132. package/types/src/lib/atlaskit/browser.d.ts +12 -0
  133. package/types/src/shared/components/toolbar/SimpleToolbarButton.d.ts +16 -0
  134. package/types/src/shared/components/toolbar/Toolbar.d.ts +4 -0
  135. package/types/src/shared/components/toolbar/ToolbarSeparator.d.ts +2 -0
  136. package/types/src/shared/components/tooltip/TooltipContent.d.ts +15 -0
  137. package/types/src/shared/hooks/useEditorForceUpdate.d.ts +2 -0
  138. package/types/src/shared/plugins/suggestion/SuggestionItem.d.ts +29 -0
  139. package/types/src/shared/plugins/suggestion/SuggestionListReactRenderer.d.ts +71 -0
  140. package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +74 -0
  141. package/types/src/shared/plugins/suggestion/components/SuggestionGroup.d.ts +23 -0
  142. package/types/src/shared/plugins/suggestion/components/SuggestionList.d.ts +26 -0
  143. package/types/src/useEditor.d.ts +8 -0
package/package.json ADDED
@@ -0,0 +1,109 @@
1
+ {
2
+ "name": "@blocknote/core",
3
+ "private": false,
4
+ "license": "MIT",
5
+ "version": "0.1.0-alpha.3",
6
+ "files": [
7
+ "dist",
8
+ "types",
9
+ "src"
10
+ ],
11
+ "keywords": [
12
+ "react",
13
+ "javascript",
14
+ "editor",
15
+ "typescript",
16
+ "prosemirror",
17
+ "wysiwyg",
18
+ "rich-text-editor",
19
+ "notion",
20
+ "yjs",
21
+ "block-based",
22
+ "tiptap"
23
+ ],
24
+ "description": "A \"Notion-style\" block-based extensible text editor built on top of Prosemirror and Tiptap.",
25
+ "type": "module",
26
+ "source": "src/index.ts",
27
+ "types": "./types/src/index.d.ts",
28
+ "main": "./dist/blocknote.umd.cjs",
29
+ "module": "./dist/blocknote.js",
30
+ "exports": {
31
+ ".": {
32
+ "import": "./dist/blocknote.js",
33
+ "require": "./dist/blocknote.umd.cjs"
34
+ },
35
+ "./style.css": {
36
+ "import": "./dist/style.css",
37
+ "require": "./dist/style.css"
38
+ }
39
+ },
40
+ "scripts": {
41
+ "dev": "vite",
42
+ "build": "tsc && vite build",
43
+ "preview": "vite preview",
44
+ "lint": "eslint src --max-warnings 0"
45
+ },
46
+ "dependencies": {
47
+ "@atlaskit/button": "^16.3.5",
48
+ "@atlaskit/dropdown-menu": "^11.1.2",
49
+ "@atlaskit/menu": "^1.3.0",
50
+ "@atlaskit/theme": "^12.1.4",
51
+ "@tippyjs/react": "^4.2.6",
52
+ "@tiptap/core": "^2.0.0-beta.182",
53
+ "@tiptap/extension-bold": "^2.0.0-beta.28",
54
+ "@tiptap/extension-code": "^2.0.0-beta.28",
55
+ "@tiptap/extension-collaboration": "^2.0.0-beta.38",
56
+ "@tiptap/extension-collaboration-cursor": "^2.0.0-beta.37",
57
+ "@tiptap/extension-dropcursor": "^2.0.0-beta.29",
58
+ "@tiptap/extension-gapcursor": "^2.0.0-beta.39",
59
+ "@tiptap/extension-hard-break": "^2.0.0-beta.33",
60
+ "@tiptap/extension-history": "^2.0.0-beta.26",
61
+ "@tiptap/extension-horizontal-rule": "^2.0.0-beta.36",
62
+ "@tiptap/extension-italic": "^2.0.0-beta.28",
63
+ "@tiptap/extension-link": "^2.0.0-beta.43",
64
+ "@tiptap/extension-paragraph": "^2.0.0-beta.26",
65
+ "@tiptap/extension-strike": "^2.0.0-beta.29",
66
+ "@tiptap/extension-text": "^2.0.0-beta.17",
67
+ "@tiptap/extension-underline": "^2.0.0-beta.25",
68
+ "@tiptap/react": "^2.0.0-beta.114",
69
+ "lodash": "^4.17.21",
70
+ "prosemirror-model": "1.18.1",
71
+ "prosemirror-state": "1.4.1",
72
+ "prosemirror-view": "1.26.2",
73
+ "react": "^17.0.2",
74
+ "react-dom": "^17.0.2",
75
+ "react-icons": "^4.3.1",
76
+ "styled-components": "^5.3.3",
77
+ "uuid": "^8.3.2"
78
+ },
79
+ "overrides": {
80
+ "react-dom": "$react-dom",
81
+ "react": "$react"
82
+ },
83
+ "devDependencies": {
84
+ "@types/lodash": "^4.14.179",
85
+ "@types/react": "^17.0.39",
86
+ "@types/react-dom": "^17.0.12",
87
+ "@types/styled-components": "^5.1.24",
88
+ "@types/uuid": "^8.3.4",
89
+ "eslint": "^8.10.0",
90
+ "eslint-config-react-app": "^7.0.0",
91
+ "typescript": "^4.5.4",
92
+ "vite": "^3.0.5",
93
+ "vite-plugin-eslint": "^1.7.0"
94
+ },
95
+ "eslintConfig": {
96
+ "extends": [
97
+ "react-app",
98
+ "react-app/jest"
99
+ ],
100
+ "rules": {
101
+ "curly": 1
102
+ }
103
+ },
104
+ "publishConfig": {
105
+ "access": "public",
106
+ "registry": "https://registry.npmjs.org/"
107
+ },
108
+ "gitHead": "806198ea45da0806b9f71010400594fdde4bbef5"
109
+ }
@@ -0,0 +1,90 @@
1
+ import { Extensions, extensions } from "@tiptap/core";
2
+
3
+ import Bold from "@tiptap/extension-bold";
4
+ import Code from "@tiptap/extension-code";
5
+ import DropCursor from "@tiptap/extension-dropcursor";
6
+ import GapCursor from "@tiptap/extension-gapcursor";
7
+ import HardBreak from "@tiptap/extension-hard-break";
8
+ import Italic from "@tiptap/extension-italic";
9
+ import Underline from "@tiptap/extension-underline";
10
+ // import Placeholder from "@tiptap/extension-placeholder";
11
+ import { Node } from "@tiptap/core";
12
+ import { History } from "@tiptap/extension-history";
13
+ import Strike from "@tiptap/extension-strike";
14
+ import Text from "@tiptap/extension-text";
15
+ import { blocks } from "./extensions/Blocks";
16
+ import blockStyles from "./extensions/Blocks/nodes/Block.module.css";
17
+ import { BubbleMenuExtension } from "./extensions/BubbleMenu/BubbleMenuExtension";
18
+ import { DraggableBlocksExtension } from "./extensions/DraggableBlocks/DraggableBlocksExtension";
19
+ import HyperlinkMark from "./extensions/Hyperlinks/HyperlinkMark";
20
+ import { FixedParagraph } from "./extensions/Paragraph/FixedParagraph";
21
+ import { Placeholder } from "./extensions/Placeholder/PlaceholderExtension";
22
+ import SlashMenuExtension from "./extensions/SlashMenu";
23
+ import { TrailingNode } from "./extensions/TrailingNode/TrailingNodeExtension";
24
+ import UniqueID from "./extensions/UniqueID/UniqueID";
25
+ export const Document = Node.create({
26
+ name: "doc",
27
+ topNode: true,
28
+ content: "block+",
29
+ });
30
+
31
+ export const getBlockNoteExtensions = () => {
32
+ const ret: Extensions = [
33
+ extensions.ClipboardTextSerializer,
34
+ extensions.Commands,
35
+ extensions.Editable,
36
+ extensions.FocusEvents,
37
+ extensions.Tabindex,
38
+
39
+ // DevTools,
40
+ GapCursor,
41
+
42
+ // DropCursor,
43
+ Placeholder.configure({
44
+ emptyNodeClass: blockStyles.isEmpty,
45
+ hasAnchorClass: blockStyles.hasAnchor,
46
+ isFilterClass: blockStyles.isFilter,
47
+ includeChildren: true,
48
+ showOnlyCurrent: false,
49
+ }),
50
+ UniqueID.configure({
51
+ types: ["tcblock"],
52
+ }),
53
+ HardBreak,
54
+ // Comments,
55
+
56
+ // basics:
57
+ Text,
58
+
59
+ // marks:
60
+ Bold,
61
+ Code,
62
+ Italic,
63
+ Strike,
64
+ Underline,
65
+ HyperlinkMark,
66
+ FixedParagraph,
67
+ // custom blocks:
68
+ ...blocks,
69
+ DraggableBlocksExtension,
70
+ DropCursor.configure({ width: 5, color: "#ddeeff" }),
71
+ BubbleMenuExtension,
72
+ History,
73
+ SlashMenuExtension,
74
+ // This needs to be at the bottom of this list, because Key events (such as enter, when selecting a /command),
75
+ // should be handled before Enter handlers in other components like splitListItem
76
+ // SlashCommandExtension.configure({
77
+ // // Extra commands can be registered here
78
+ // commands: {},
79
+ // }),
80
+ // MentionsExtension.configure({
81
+ // providers: {
82
+ // people: (query) => {
83
+ // return PEOPLE.filter((mention) => mention.match(query));
84
+ // },
85
+ // },
86
+ // }),
87
+ TrailingNode,
88
+ ];
89
+ return ret;
90
+ };
@@ -0,0 +1 @@
1
+ export { EditorContent } from "@tiptap/react";
@@ -0,0 +1,3 @@
1
+ .bnEditor {
2
+ outline: none;
3
+ }
@@ -0,0 +1,46 @@
1
+ import { Plugin, PluginKey } from "prosemirror-state";
2
+
3
+ const PLUGIN_KEY = new PluginKey(`ordered-list`);
4
+
5
+ export const OrderedListPlugin = () => {
6
+ return new Plugin({
7
+ key: PLUGIN_KEY,
8
+ appendTransaction: (_transactions, _oldState, newState) => {
9
+ const newTr = newState.tr;
10
+ let modified = false;
11
+ let count = 1;
12
+ let skip = 0;
13
+ newState.doc.descendants((node, pos) => {
14
+ if (node.type.name === "tcblock" && !node.attrs.listType) {
15
+ count = 1;
16
+ }
17
+ if (
18
+ skip === 0 &&
19
+ node.type.name === "tcblock" &&
20
+ node.attrs.listType === "oli"
21
+ ) {
22
+ skip = node.content.childCount;
23
+ // This assumes that the content node is always the first child of the oli block,
24
+ // as the content model grows this assumption may need to change
25
+ if (node.content.child(0).attrs.position !== `${count}.`) {
26
+ // TODO: @DAlperin currently sub-items just continue from the order of the parent,
27
+ // sub-items should be ordered separately with letters or roman numerals or some such
28
+ newTr.setNodeMarkup(pos + 1, undefined, {
29
+ ...node.attrs,
30
+ position: `${count}.`,
31
+ });
32
+ modified = true;
33
+ }
34
+
35
+ count++;
36
+ } else if (skip > 0) {
37
+ skip--;
38
+ }
39
+ });
40
+ if (modified) {
41
+ return newTr;
42
+ }
43
+ return null;
44
+ },
45
+ });
46
+ };
@@ -0,0 +1,146 @@
1
+ import {
2
+ combineTransactionSteps,
3
+ findChildren,
4
+ getChangedRanges,
5
+ } from "@tiptap/core";
6
+ import { Plugin, PluginKey } from "prosemirror-state";
7
+ import { Decoration, DecorationSet } from "prosemirror-view";
8
+
9
+ const PLUGIN_KEY = new PluginKey(`previous-blocks`);
10
+
11
+ /**
12
+ * This plugin tracks transformation of Block node attributes, so we can support CSS transitions.
13
+ *
14
+ * Problem it solves: Prosemirror recreates the DOM when transactions happen. So when a transaction changes an Node attribute,
15
+ * it results in a completely new DOM element. This means CSS transitions don't work.
16
+ *
17
+ * Solution: When attributes change on a node, this plugin sets a data-* attribute with the "previous" value. This way we can still use CSS transitions. (See block.module.css)
18
+ */
19
+ export const PreviousBlockTypePlugin = () => {
20
+ return new Plugin({
21
+ key: PLUGIN_KEY,
22
+ view(_editorView) {
23
+ return {
24
+ update: async (view, _prevState) => {
25
+ if (this.key?.getState(view.state).needsUpdate) {
26
+ // use setTimeout 0 to clear the decorations so that at least
27
+ // for one DOM-render the decorations have been applied
28
+ setTimeout(() => {
29
+ view.dispatch(
30
+ view.state.tr.setMeta(PLUGIN_KEY, { clearUpdate: true })
31
+ );
32
+ }, 0);
33
+ }
34
+ },
35
+ };
36
+ },
37
+ state: {
38
+ init() {
39
+ return {
40
+ prevBlockAttrs: {} as any,
41
+ needsUpdate: false,
42
+ };
43
+ },
44
+
45
+ apply(transaction, prev, oldState, newState) {
46
+ prev.needsUpdate = false;
47
+ prev.prevBlockAttrs = {};
48
+ if (!transaction.docChanged || oldState.doc.eq(newState.doc)) {
49
+ return prev;
50
+ }
51
+
52
+ const transform = combineTransactionSteps(oldState.doc, [transaction]);
53
+ // const { mapping } = transform;
54
+ const changes = getChangedRanges(transform);
55
+
56
+ // TODO: instead of iterating through the entire document, only check nodes affected by the transactions
57
+ // We didn't get this to work yet:
58
+ // changes.forEach(({ oldRange, newRange }) => {
59
+ // const oldNodes = findChildrenInRange(
60
+ // oldState.doc,
61
+ // oldRange,
62
+ // (node) => node.attrs.id
63
+ // );
64
+
65
+ // const newNodes = findChildrenInRange(
66
+ // newState.doc,
67
+ // newRange,
68
+ // (node) => node.attrs.id
69
+ // );
70
+
71
+ changes.forEach(() => {
72
+ const oldNodes = findChildren(oldState.doc, (node) => node.attrs.id);
73
+
74
+ const oldNodesById = new Map(
75
+ oldNodes.map((node) => [node.node.attrs.id, node])
76
+ );
77
+
78
+ const newNodes = findChildren(newState.doc, (node) => node.attrs.id);
79
+
80
+ for (let node of newNodes) {
81
+ const oldNode = oldNodesById.get(node.node.attrs.id);
82
+ if (oldNode) {
83
+ const newAttrs = {
84
+ listType: node.node.attrs.listType,
85
+ blockColor: node.node.attrs.blockColor,
86
+ blockStyle: node.node.attrs.blockStyle,
87
+ headingType: node.node.attrs.headingType,
88
+ depth: newState.doc.resolve(node.pos).depth,
89
+ };
90
+
91
+ const oldAttrs = {
92
+ listType: oldNode.node.attrs.listType,
93
+ blockColor: oldNode.node.attrs.blockColor,
94
+ blockStyle: oldNode.node.attrs.blockStyle,
95
+ headingType: oldNode.node.attrs.headingType,
96
+ depth: oldState.doc.resolve(oldNode.pos).depth,
97
+ };
98
+
99
+ if (
100
+ JSON.stringify(oldAttrs) !== JSON.stringify(newAttrs) // TODO: faster deep equal?
101
+ ) {
102
+ (oldAttrs as any).depthChange = oldAttrs.depth - newAttrs.depth;
103
+ prev.prevBlockAttrs[node.node.attrs.id] = oldAttrs;
104
+ prev.needsUpdate = true;
105
+ }
106
+ }
107
+ }
108
+ });
109
+
110
+ return prev;
111
+ },
112
+ },
113
+ props: {
114
+ decorations(state) {
115
+ const pluginState = (this as Plugin).getState(state);
116
+ if (!pluginState.needsUpdate) {
117
+ return undefined;
118
+ }
119
+
120
+ const decorations: Decoration[] = [];
121
+
122
+ state.doc.descendants((node, pos) => {
123
+ if (!node.attrs.id) {
124
+ return;
125
+ }
126
+ const prevAttrs = pluginState.prevBlockAttrs[node.attrs.id];
127
+ if (!prevAttrs) {
128
+ return;
129
+ }
130
+
131
+ const decorationAttributes: any = {};
132
+ for (let [key, val] of Object.entries(prevAttrs)) {
133
+ decorationAttributes["data-prev-" + key] = val || "none";
134
+ }
135
+ const decoration = Decoration.node(pos, pos + node.nodeSize, {
136
+ ...decorationAttributes,
137
+ });
138
+
139
+ decorations.push(decoration);
140
+ });
141
+
142
+ return DecorationSet.create(state.doc, decorations);
143
+ },
144
+ },
145
+ });
146
+ };