@blocknote/core 0.1.0-alpha.3 → 0.1.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/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@blocknote/core",
3
+ "homepage": "https://github.com/yousefed/blocknote",
3
4
  "private": false,
4
- "license": "MIT",
5
- "version": "0.1.0-alpha.3",
5
+ "license": "MPL-2.0",
6
+ "version": "0.1.0",
6
7
  "files": [
7
8
  "dist",
8
9
  "types",
@@ -105,5 +106,5 @@
105
106
  "access": "public",
106
107
  "registry": "https://registry.npmjs.org/"
107
108
  },
108
- "gitHead": "806198ea45da0806b9f71010400594fdde4bbef5"
109
+ "gitHead": "511cb65b707ca40289d838c71ac6edd29d882eef"
109
110
  }
@@ -1,17 +1,16 @@
1
1
  import { Extensions, extensions } from "@tiptap/core";
2
2
 
3
+ import { Node } from "@tiptap/core";
3
4
  import Bold from "@tiptap/extension-bold";
4
5
  import Code from "@tiptap/extension-code";
5
6
  import DropCursor from "@tiptap/extension-dropcursor";
6
7
  import GapCursor from "@tiptap/extension-gapcursor";
7
8
  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
9
  import { History } from "@tiptap/extension-history";
10
+ import Italic from "@tiptap/extension-italic";
13
11
  import Strike from "@tiptap/extension-strike";
14
12
  import Text from "@tiptap/extension-text";
13
+ import Underline from "@tiptap/extension-underline";
15
14
  import { blocks } from "./extensions/Blocks";
16
15
  import blockStyles from "./extensions/Blocks/nodes/Block.module.css";
17
16
  import { BubbleMenuExtension } from "./extensions/BubbleMenu/BubbleMenuExtension";
@@ -22,12 +21,16 @@ import { Placeholder } from "./extensions/Placeholder/PlaceholderExtension";
22
21
  import SlashMenuExtension from "./extensions/SlashMenu";
23
22
  import { TrailingNode } from "./extensions/TrailingNode/TrailingNodeExtension";
24
23
  import UniqueID from "./extensions/UniqueID/UniqueID";
24
+
25
25
  export const Document = Node.create({
26
26
  name: "doc",
27
27
  topNode: true,
28
28
  content: "block+",
29
29
  });
30
30
 
31
+ /**
32
+ * Get all the Tiptap extensions BlockNote is configured with by default
33
+ */
31
34
  export const getBlockNoteExtensions = () => {
32
35
  const ret: Extensions = [
33
36
  extensions.ClipboardTextSerializer,
@@ -48,7 +51,7 @@ export const getBlockNoteExtensions = () => {
48
51
  showOnlyCurrent: false,
49
52
  }),
50
53
  UniqueID.configure({
51
- types: ["tcblock"],
54
+ types: ["block"],
52
55
  }),
53
56
  HardBreak,
54
57
  // Comments,
@@ -64,26 +67,16 @@ export const getBlockNoteExtensions = () => {
64
67
  Underline,
65
68
  HyperlinkMark,
66
69
  FixedParagraph,
70
+
67
71
  // custom blocks:
68
72
  ...blocks,
69
73
  DraggableBlocksExtension,
70
74
  DropCursor.configure({ width: 5, color: "#ddeeff" }),
71
75
  BubbleMenuExtension,
72
76
  History,
73
- SlashMenuExtension,
74
77
  // This needs to be at the bottom of this list, because Key events (such as enter, when selecting a /command),
75
78
  // 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
- // }),
79
+ SlashMenuExtension,
87
80
  TrailingNode,
88
81
  ];
89
82
  return ret;
@@ -1 +1,2 @@
1
- export { EditorContent } from "@tiptap/react";
1
+ // BlockNote uses a similar pattern as Tiptap, so for now we can just export that
2
+ export { EditorContent } from "@tiptap/react";
@@ -11,12 +11,12 @@ export const OrderedListPlugin = () => {
11
11
  let count = 1;
12
12
  let skip = 0;
13
13
  newState.doc.descendants((node, pos) => {
14
- if (node.type.name === "tcblock" && !node.attrs.listType) {
14
+ if (node.type.name === "block" && !node.attrs.listType) {
15
15
  count = 1;
16
16
  }
17
17
  if (
18
18
  skip === 0 &&
19
- node.type.name === "tcblock" &&
19
+ node.type.name === "block" &&
20
20
  node.attrs.listType === "oli"
21
21
  ) {
22
22
  skip = node.content.childCount;
@@ -1,3 +1,3 @@
1
1
  import { findParentNode } from "@tiptap/core";
2
2
 
3
- export const findBlock = findParentNode((node) => node.type.name === "tcblock");
3
+ export const findBlock = findParentNode((node) => node.type.name === "block");
@@ -43,7 +43,7 @@ declare module "@tiptap/core" {
43
43
  * The main "Block node" documents consist of
44
44
  */
45
45
  export const Block = Node.create<IBlock>({
46
- name: "tcblock",
46
+ name: "block",
47
47
  group: "block",
48
48
  addOptions() {
49
49
  return {
@@ -52,7 +52,7 @@ export const Block = Node.create<IBlock>({
52
52
  },
53
53
 
54
54
  // A block always contains content, and optionally a blockGroup which contains nested blocks
55
- content: "tccontent blockgroup?",
55
+ content: "content blockgroup?",
56
56
 
57
57
  defining: true,
58
58
 
@@ -172,7 +172,7 @@ export const Block = Node.create<IBlock>({
172
172
  const nodePos = tr.selection.$anchor.posAtIndex(0, -1) - 1;
173
173
 
174
174
  // const node2 = tr.doc.nodeAt(nodePos);
175
- if (node.type.name === "tcblock" && node.attrs["listType"]) {
175
+ if (node.type.name === "block" && node.attrs["listType"]) {
176
176
  if (dispatch) {
177
177
  tr.setNodeMarkup(nodePos, undefined, {
178
178
  ...node.attrs,
@@ -203,8 +203,7 @@ export const Block = Node.create<IBlock>({
203
203
 
204
204
  // Create new block after current block
205
205
  const endOfBlock = currentBlock.pos + currentBlock.node.nodeSize;
206
- let newBlock =
207
- state.schema.nodes["tcblock"].createAndFill(attributes)!;
206
+ let newBlock = state.schema.nodes["block"].createAndFill(attributes)!;
208
207
  if (dispatch) {
209
208
  tr.insert(endOfBlock, newBlock);
210
209
  tr.setSelection(new TextSelection(tr.doc.resolve(endOfBlock + 1)));
@@ -218,7 +217,7 @@ export const Block = Node.create<IBlock>({
218
217
  const nodePos = tr.selection.$anchor.posAtIndex(0, -1) - 1;
219
218
 
220
219
  // const node2 = tr.doc.nodeAt(nodePos);
221
- if (node.type.name === "tcblock") {
220
+ if (node.type.name === "block") {
222
221
  if (dispatch) {
223
222
  tr.setNodeMarkup(nodePos, undefined, {
224
223
  ...node.attrs,
@@ -268,11 +267,11 @@ export const Block = Node.create<IBlock>({
268
267
  commands.command(({ tr }) => {
269
268
  const isAtStartOfNode = tr.selection.$anchor.parentOffset === 0;
270
269
  const node = tr.selection.$anchor.node(-1);
271
- if (isAtStartOfNode && node.type.name === "tcblock") {
270
+ if (isAtStartOfNode && node.type.name === "block") {
272
271
  // we're at the start of the block, so we're trying to "backspace" the bullet or indentation
273
272
  return commands.first([
274
273
  () => commands.unsetList(), // first try to remove the "list" property
275
- () => commands.liftListItem("tcblock"), // then try to remove a level of indentation
274
+ () => commands.liftListItem("block"), // then try to remove a level of indentation
276
275
  ]);
277
276
  }
278
277
  return false;
@@ -292,7 +291,7 @@ export const Block = Node.create<IBlock>({
292
291
  const isAtStartOfNode = tr.selection.$anchor.parentOffset === 0;
293
292
  const anchor = tr.selection.$anchor;
294
293
  const node = anchor.node(-1);
295
- if (isAtStartOfNode && node.type.name === "tcblock") {
294
+ if (isAtStartOfNode && node.type.name === "block") {
296
295
  if (node.childCount === 2) {
297
296
  // BlockB has children. We want to go from this:
298
297
  //
@@ -337,7 +336,7 @@ export const Block = Node.create<IBlock>({
337
336
  const handleEnter = () =>
338
337
  this.editor.commands.first(({ commands }) => [
339
338
  // Try to split the current block into 2 items:
340
- () => commands.splitListItem("tcblock"),
339
+ () => commands.splitListItem("block"),
341
340
  // Otherwise, maybe we are in an empty list item. "Enter" should remove the list bullet
342
341
  ({ tr, dispatch }) => {
343
342
  const $from = tr.selection.$from;
@@ -348,7 +347,7 @@ export const Block = Node.create<IBlock>({
348
347
  const node = tr.selection.$anchor.node(-1);
349
348
  const nodePos = tr.selection.$anchor.posAtIndex(0, -1) - 1;
350
349
 
351
- if (node.type.name === "tcblock" && node.attrs["listType"]) {
350
+ if (node.type.name === "block" && node.attrs["listType"]) {
352
351
  if (dispatch) {
353
352
  tr.setNodeMarkup(nodePos, undefined, {
354
353
  ...node.attrs,
@@ -373,9 +372,9 @@ export const Block = Node.create<IBlock>({
373
372
  return {
374
373
  Backspace: handleBackspace,
375
374
  Enter: handleEnter,
376
- Tab: () => this.editor.commands.sinkListItem("tcblock"),
375
+ Tab: () => this.editor.commands.sinkListItem("block"),
377
376
  "Shift-Tab": () => {
378
- return this.editor.commands.liftListItem("tcblock");
377
+ return this.editor.commands.liftListItem("block");
379
378
  },
380
379
  "Mod-Alt-0": () =>
381
380
  this.editor.chain().unsetList().unsetBlockHeading().run(),
@@ -10,7 +10,7 @@ export const BlockGroup = Node.create({
10
10
  };
11
11
  },
12
12
 
13
- content: "tcblock+",
13
+ content: "block+",
14
14
 
15
15
  parseHTML() {
16
16
  return [{ tag: "div" }];
@@ -5,7 +5,7 @@ export interface IBlock {
5
5
  }
6
6
 
7
7
  export const ContentBlock = Node.create<IBlock>({
8
- name: "tccontent",
8
+ name: "content",
9
9
 
10
10
  addOptions() {
11
11
  return {
@@ -1,9 +1,10 @@
1
1
  import { Extension } from "@tiptap/core";
2
2
  import { PluginKey } from "prosemirror-state";
3
3
  import ReactDOM from "react-dom";
4
+ import rootStyles from "../../root.module.css";
4
5
  import { createBubbleMenuPlugin } from "./BubbleMenuPlugin";
5
6
  import { BubbleMenu } from "./component/BubbleMenu";
6
- import rootStyles from "../../root.module.css";
7
+
7
8
  /**
8
9
  * The menu that is displayed when selecting a piece of text.
9
10
  */
@@ -1,27 +1,27 @@
1
+ import DropdownMenu, { DropdownItemGroup } from "@atlaskit/dropdown-menu";
1
2
  import { Editor } from "@tiptap/core";
2
3
  import {
3
4
  RiBold,
4
5
  RiH1,
5
6
  RiH2,
6
7
  RiH3,
8
+ RiIndentDecrease,
9
+ RiIndentIncrease,
7
10
  RiItalic,
8
11
  RiLink,
9
- RiStrikethrough,
10
- RiUnderline,
11
- RiIndentIncrease,
12
- RiIndentDecrease,
13
- RiText,
14
12
  RiListOrdered,
15
13
  RiListUnordered,
14
+ RiStrikethrough,
15
+ RiText,
16
+ RiUnderline,
16
17
  } from "react-icons/ri";
17
18
  import { SimpleToolbarButton } from "../../../shared/components/toolbar/SimpleToolbarButton";
18
19
  import { Toolbar } from "../../../shared/components/toolbar/Toolbar";
19
20
  import { useEditorForceUpdate } from "../../../shared/hooks/useEditorForceUpdate";
20
21
  import { findBlock } from "../../Blocks/helpers/findBlock";
21
22
  import formatKeyboardShortcut from "../../helpers/formatKeyboardShortcut";
22
- import LinkToolbarButton from "./LinkToolbarButton";
23
- import DropdownMenu, { DropdownItemGroup } from "@atlaskit/dropdown-menu";
24
23
  import DropdownBlockItem from "./DropdownBlockItem";
24
+ import LinkToolbarButton from "./LinkToolbarButton";
25
25
 
26
26
  type ListType = "li" | "oli";
27
27
 
@@ -167,19 +167,15 @@ export const BubbleMenu = (props: { editor: Editor }) => {
167
167
  icon={RiStrikethrough}
168
168
  />
169
169
  <SimpleToolbarButton
170
- onClick={() =>
171
- props.editor.chain().focus().sinkListItem("tcblock").run()
172
- }
173
- isDisabled={!props.editor.can().sinkListItem("tcblock")}
170
+ onClick={() => props.editor.chain().focus().sinkListItem("block").run()}
171
+ isDisabled={!props.editor.can().sinkListItem("block")}
174
172
  mainTooltip="Indent"
175
173
  secondaryTooltip={formatKeyboardShortcut("Tab")}
176
174
  icon={RiIndentIncrease}
177
175
  />
178
176
 
179
177
  <SimpleToolbarButton
180
- onClick={() =>
181
- props.editor.chain().focus().liftListItem("tcblock").run()
182
- }
178
+ onClick={() => props.editor.chain().focus().liftListItem("block").run()}
183
179
  isDisabled={
184
180
  !props.editor.can().command(({ state }) => {
185
181
  const block = findBlock(state.selection);
@@ -59,8 +59,7 @@ export const DragHandle = (props: {
59
59
  if (currentBlock.node.firstChild?.textContent.length !== 0) {
60
60
  // Create new block after current block
61
61
  const endOfBlock = currentBlock.pos + currentBlock.node.nodeSize;
62
- let newBlock =
63
- props.view.state.schema.nodes["tccontent"].createAndFill()!;
62
+ let newBlock = props.view.state.schema.nodes["content"].createAndFill()!;
64
63
  props.view.state.tr.insert(endOfBlock, newBlock);
65
64
  props.view.dispatch(props.view.state.tr.insert(endOfBlock, newBlock));
66
65
  props.view.dispatch(
@@ -13,6 +13,9 @@ export interface TrailingNodeOptions {
13
13
  node: string;
14
14
  }
15
15
 
16
+ /**
17
+ * Add a trailing node to the document so the user can always click at the bottom of the document and start typing
18
+ */
16
19
  export const TrailingNode = Extension.create<TrailingNodeOptions>({
17
20
  name: "trailingNode",
18
21
 
@@ -29,8 +32,8 @@ export const TrailingNode = Extension.create<TrailingNodeOptions>({
29
32
  const { doc, tr, schema } = state;
30
33
  const shouldInsertNodeAtEnd = plugin.getState(state);
31
34
  const endPosition = doc.content.size - 2;
32
- const type = schema.nodes["tcblock"];
33
- const contenttype = schema.nodes["tccontent"];
35
+ const type = schema.nodes["block"];
36
+ const contenttype = schema.nodes["content"];
34
37
  if (!shouldInsertNodeAtEnd) {
35
38
  return;
36
39
  }
@@ -58,10 +61,10 @@ export const TrailingNode = Extension.create<TrailingNodeOptions>({
58
61
 
59
62
  lastNode = lastNode.lastChild;
60
63
 
61
- if (!lastNode || lastNode.type.name !== "tcblock") {
62
- throw new Error("Expected tcblock");
64
+ if (!lastNode || lastNode.type.name !== "block") {
65
+ throw new Error("Expected block");
63
66
  }
64
- return lastNode.nodeSize > 4; // empty <tcblock><tccontent/></tcblock> is length 4
67
+ return lastNode.nodeSize > 4; // empty <block><content/></block> is length 4
65
68
  },
66
69
  },
67
70
  }),
package/src/useEditor.ts CHANGED
@@ -17,6 +17,10 @@ const blockNoteOptions = {
17
17
  enablePasteRules: true,
18
18
  enableCoreExtensions: false,
19
19
  };
20
+
21
+ /**
22
+ * Main hook for importing a BlockNote editor into a react project
23
+ */
20
24
  export const useEditor = (
21
25
  options: Partial<BlockNoteEditorOptions> = {},
22
26
  deps: DependencyList = []
@@ -1,4 +1,7 @@
1
1
  import { Extensions } from "@tiptap/core";
2
2
  import { Node } from "@tiptap/core";
3
3
  export declare const Document: Node<any, any>;
4
+ /**
5
+ * Get all the Tiptap extensions BlockNote is configured with by default
6
+ */
4
7
  export declare const getBlockNoteExtensions: () => Extensions;
@@ -7,4 +7,7 @@ import { Extension } from "@tiptap/core";
7
7
  export interface TrailingNodeOptions {
8
8
  node: string;
9
9
  }
10
+ /**
11
+ * Add a trailing node to the document so the user can always click at the bottom of the document and start typing
12
+ */
10
13
  export declare const TrailingNode: Extension<TrailingNodeOptions, any>;
@@ -4,5 +4,8 @@ declare type BlockNoteEditorOptions = EditorOptions & {
4
4
  enableBlockNoteExtensions: boolean;
5
5
  disableHistoryExtension: boolean;
6
6
  };
7
+ /**
8
+ * Main hook for importing a BlockNote editor into a react project
9
+ */
7
10
  export declare const useEditor: (options?: Partial<BlockNoteEditorOptions>, deps?: DependencyList) => import("@tiptap/react").Editor | null;
8
11
  export {};
@@ -1,26 +0,0 @@
1
- # Node structure
2
-
3
- We use the following document structure:
4
-
5
- ```xml
6
- <blockgroup>
7
- <block>
8
- <content>Parent element 1</content>
9
- <blockgroup>
10
- <block>
11
- <content>Nested / child / indented item</content>
12
- </block>
13
- </blockgroup>
14
- </block>
15
- <block>
16
- <content>Parent element 2</content>
17
- <blockgroup>
18
- <block>...</block>
19
- <block>...</block>
20
- </blockgroup>
21
- </block>
22
- <block>
23
- <content>Element 3 without children</content>
24
- </block>
25
- </blockgroup>
26
- ```