-
Community contributors
+
Open Source Community
Join a community of open-source contributors by tuning in with the
BlockNote community and contributing to the project.
@@ -19,7 +19,7 @@ export const Community: FC = () => (
(
Why BlockNote?
- Whether you want deep customization or a great out-of-the-box
- experience, BlockNote has you covered with features for any use
- case.
+ Whether you want extensive customization or a great out-of-the-box
+ experience, BlockNote has you covered:
{featuresCardData.map((feature) => (
))}
+ ...and more: (TODO)
+
+ - Helpful Placeholders
+ - Smooth Animations
+ - Image Uploads
+ - Resizable Tables
+
diff --git a/docs/components/pages/landing/hero/Demo.tsx b/docs/components/pages/landing/hero/Demo.tsx
index c2ad2fff55..ac3b93633f 100644
--- a/docs/components/pages/landing/hero/Demo.tsx
+++ b/docs/components/pages/landing/hero/Demo.tsx
@@ -1,7 +1,7 @@
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
import { BlockNoteView, useCreateBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";
-import { useMemo } from "react";
+import { useCallback, useMemo, useState } from "react";
import YPartyKitProvider from "y-partykit/provider";
import * as Y from "yjs";
@@ -81,24 +81,18 @@ export function ReactBlockNote(props: { theme: "light" | "dark" }) {
[],
);
- // TODO
- // useEffect(() => {
- // let shownAlert = false;
- // const listener = () => {
- // if (!shownAlert) {
- // alert(
- // "Text you enter in this demo is displayed publicly on the internet to show multiplayer features. Be kind :)",
- // );
- // shownAlert = true;
- // }
- // };
- // editor?.domElement?.addEventListener("focus", listener);
- // return () => {
- // editor?.domElement?.removeEventListener("focus", listener);
- // };
- // }, [editor?.domElement]);
+ const [warningShown, setWarningShown] = useState(false);
- return
;
+ const focus = useCallback(() => {
+ if (!warningShown) {
+ alert(
+ "Text you enter in this demo is displayed publicly on the internet to show multiplayer features. Be kind :)",
+ );
+ setWarningShown(true);
+ }
+ }, [warningShown]);
+
+ return
;
}
export default ReactBlockNote;
diff --git a/docs/components/pages/landing/index.tsx b/docs/components/pages/landing/index.tsx
index 564e89c18c..f5089fa037 100644
--- a/docs/components/pages/landing/index.tsx
+++ b/docs/components/pages/landing/index.tsx
@@ -2,12 +2,12 @@ import { Features } from "./features/Features";
import { Hero } from "./hero/Hero";
import { Letter } from "./letter/Letter";
+import { Community } from "@/components/pages/landing/community/Community";
import { FadeIn } from "@/components/pages/landing/shared/FadeIn";
+import { Sponsors } from "@/components/pages/landing/sponsors/Sponsors";
import FAQ from "./FAQ";
import "./gradients.css";
import "./styles.css";
-import { Sponsors } from "@/components/pages/landing/sponsors/Sponsors";
-import { Community } from "@/components/pages/landing/community/Community";
// TODO: Cleanup
export function BlockNoteHome() {
diff --git a/docs/components/pages/landing/sponsors/SponsorCard.tsx b/docs/components/pages/landing/sponsors/SponsorCard.tsx
index 879c99ee6c..3d7144d11b 100644
--- a/docs/components/pages/landing/sponsors/SponsorCard.tsx
+++ b/docs/components/pages/landing/sponsors/SponsorCard.tsx
@@ -23,7 +23,7 @@ export function SponsorCard(props: SponsorCardProps) {
alt={props.name}
/>
{props.tagline && (
-
+
{props.tagline}
)}
diff --git a/docs/components/pages/landing/sponsors/Sponsors.tsx b/docs/components/pages/landing/sponsors/Sponsors.tsx
index 1ba738377c..133714744b 100644
--- a/docs/components/pages/landing/sponsors/Sponsors.tsx
+++ b/docs/components/pages/landing/sponsors/Sponsors.tsx
@@ -1,22 +1,22 @@
-import { SectionHeader } from "../../home-shared/Headings";
-import { FadeIn } from "../shared/FadeIn";
import {
SponsorCard,
SponsorCardProps,
} from "@/components/pages/landing/sponsors/SponsorCard";
+import { SectionHeader } from "../../home-shared/Headings";
+import { FadeIn } from "../shared/FadeIn";
-import fermatLight from "../../../../public/img/sponsors/fermat.png";
import fermatDark from "../../../../public/img/sponsors/fermat-dark.png";
-import nlnetLight from "../../../../public/img/sponsors/nlnet.svg";
+import fermatLight from "../../../../public/img/sponsors/fermat.png";
import nlnetDark from "../../../../public/img/sponsors/nlnet-dark.svg";
-import typecellLight from "../../../../public/img/sponsors/typecell.svg";
-import typecellDark from "../../../../public/img/sponsors/typecell-dark.svg";
-import poggioLight from "../../../../public/img/sponsors/poggio.svg";
+import nlnetLight from "../../../../public/img/sponsors/nlnet.svg";
+import noteplanDark from "../../../../public/img/sponsors/noteplan-dark.png";
+import noteplanLight from "../../../../public/img/sponsors/noteplan.png";
import poggioDark from "../../../../public/img/sponsors/poggio-dark.svg";
-import twentyLight from "../../../../public/img/sponsors/twenty.png";
+import poggioLight from "../../../../public/img/sponsors/poggio.svg";
import twentyDark from "../../../../public/img/sponsors/twenty-dark.png";
-import noteplanLight from "../../../../public/img/sponsors/noteplan.png";
-import noteplanDark from "../../../../public/img/sponsors/noteplan-dark.png";
+import twentyLight from "../../../../public/img/sponsors/twenty.png";
+import typecellDark from "../../../../public/img/sponsors/typecell-dark.svg";
+import typecellLight from "../../../../public/img/sponsors/typecell.svg";
export const sponsorsCardData: SponsorCardProps[] = [
{
@@ -53,7 +53,7 @@ export const sponsorsCardData: SponsorCardProps[] = [
dark: twentyDark,
},
name: "Twenty",
- tagline: "Y Combinator S23",
+ tagline: "YC S23",
},
{
logo: {
@@ -61,6 +61,7 @@ export const sponsorsCardData: SponsorCardProps[] = [
dark: noteplanDark,
},
name: "Noteplan",
+ tagline: "Apple Top Notes Apps",
},
];
diff --git a/docs/pages/docs/_meta.json b/docs/pages/docs/_meta.json
index 9d5049f9ce..4b8c99d576 100644
--- a/docs/pages/docs/_meta.json
+++ b/docs/pages/docs/_meta.json
@@ -7,7 +7,6 @@
"ui-components": "UI Components",
"custom-schemas": "Custom Schemas",
"advanced": "Advanced",
- "glossary":"",
"discord-link": {
"title": "Community ↗",
"href": "https://discord.gg/Qc2QTTH5dF",
diff --git a/docs/pages/docs/editor-api/manipulating-inline-content.mdx b/docs/pages/docs/editor-api/manipulating-inline-content.mdx
index 0f90561e11..6f5129ce07 100644
--- a/docs/pages/docs/editor-api/manipulating-inline-content.mdx
+++ b/docs/pages/docs/editor-api/manipulating-inline-content.mdx
@@ -1,6 +1,5 @@
---
title: Manipulating Inline Content
-description: TODO
imageTitle: Manipulating Inline Content
path: /docs/block-content
---
diff --git a/docs/pages/features.mdx.bak b/docs/pages/features.mdx.bak
new file mode 100644
index 0000000000..77f95c3e93
--- /dev/null
+++ b/docs/pages/features.mdx.bak
@@ -0,0 +1,10 @@
+---
+overrideTitle: "BlockNote - Javascript Block-Based React rich text editor"
+description: "A beautiful text editor that just works. Easily add an editor to your app that users will love. Customize it with your own functionality like custom blocks or AI tooling."
+---
+
+import Feature from "@/components/Feature";
+
+
+
+
diff --git a/examples/04-interoperability/02-converting-blocks-from-html/App.tsx b/examples/04-interoperability/02-converting-blocks-from-html/App.tsx
index 9bcdd9f5c6..35d3f8150f 100644
--- a/examples/04-interoperability/02-converting-blocks-from-html/App.tsx
+++ b/examples/04-interoperability/02-converting-blocks-from-html/App.tsx
@@ -6,7 +6,6 @@ import "./styles.css";
const initialHTML = "
Hello, world!
";
-// TODO: better design?
export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote();
diff --git a/examples/04-interoperability/04-converting-blocks-from-md/App.tsx b/examples/04-interoperability/04-converting-blocks-from-md/App.tsx
index 49629851e2..3c4b3cb6b8 100644
--- a/examples/04-interoperability/04-converting-blocks-from-md/App.tsx
+++ b/examples/04-interoperability/04-converting-blocks-from-md/App.tsx
@@ -2,7 +2,6 @@ import { BlockNoteView, useCreateBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";
import { ChangeEvent, useCallback, useEffect } from "react";
-// TODO: better design?
const initialMarkdown = "Hello, **world!**";
export default function App() {
diff --git a/examples/05-custom-schema/react-custom-styles/App.tsx b/examples/05-custom-schema/react-custom-styles/App.tsx
index 096d2a76f4..25e435f91e 100644
--- a/examples/05-custom-schema/react-custom-styles/App.tsx
+++ b/examples/05-custom-schema/react-custom-styles/App.tsx
@@ -106,7 +106,7 @@ export default function App() {
);
return (
-
+
diff --git a/examples/06-collaboration/01-partykit/.bnexample.json b/examples/06-collaboration/01-partykit/.bnexample.json
index 9c252f12aa..d0a7ffb081 100644
--- a/examples/06-collaboration/01-partykit/.bnexample.json
+++ b/examples/06-collaboration/01-partykit/.bnexample.json
@@ -4,7 +4,7 @@
"author": "matthewlipski",
"tags": ["Advanced", "Saving/Loading", "Collaboration"],
"dependencies": {
- "y-partykit": "^0.0.10",
+ "y-partykit": "^0.0.25",
"yjs": "^13.6.1"
}
}
diff --git a/examples/06-collaboration/01-partykit/package.json b/examples/06-collaboration/01-partykit/package.json
index aacb4edc95..bbfef6771b 100644
--- a/examples/06-collaboration/01-partykit/package.json
+++ b/examples/06-collaboration/01-partykit/package.json
@@ -15,7 +15,7 @@
"@blocknote/react": "^0.11.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "y-partykit": "^0.0.10",
+ "y-partykit": "^0.0.25",
"yjs": "^13.6.1"
},
"devDependencies": {
diff --git a/examples/vanilla-js/react-vanilla-custom-blocks/App.tsx b/examples/vanilla-js/react-vanilla-custom-blocks/App.tsx
index 1117fe1168..886f562571 100644
--- a/examples/vanilla-js/react-vanilla-custom-blocks/App.tsx
+++ b/examples/vanilla-js/react-vanilla-custom-blocks/App.tsx
@@ -56,7 +56,6 @@ const alertBlock = createBlockSpec(
const dropdown = document.createElement("select");
dropdown.contentEditable = "false";
dropdown.addEventListener("change", () => {
- // TODO: Something is not quite right with the typing seems like
editor.updateBlock(block, {
type: "alert",
props: { type: dropdown.value as keyof typeof alertTypes },
diff --git a/examples/vanilla-js/react-vanilla-custom-styles/App.tsx b/examples/vanilla-js/react-vanilla-custom-styles/App.tsx
index e784e575bb..84eb79e917 100644
--- a/examples/vanilla-js/react-vanilla-custom-styles/App.tsx
+++ b/examples/vanilla-js/react-vanilla-custom-styles/App.tsx
@@ -119,7 +119,7 @@ export default function App() {
);
return (
-
+
diff --git a/package-lock.json b/package-lock.json
index 8567786823..5049269b06 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21225,16 +21225,6 @@
"node": ">=0.4"
}
},
- "node_modules/y-partykit": {
- "version": "0.0.0-fffe721",
- "license": "ISC",
- "dependencies": {
- "lib0": "^0.2.60",
- "lodash.debounce": "^4.0.8",
- "y-protocols": "^1.0.5",
- "yjs": "^13.5.44"
- }
- },
"node_modules/y-prosemirror": {
"version": "1.0.20",
"license": "MIT",
@@ -21552,7 +21542,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
- "y-partykit": "^0.0.0-4c022c1",
+ "y-partykit": "^0.0.25",
"yjs": "^13.6.10"
},
"devDependencies": {
@@ -21566,6 +21556,25 @@
"vite-plugin-eslint": "^1.8.1"
}
},
+ "playground/node_modules/lib0": {
+ "version": "0.2.90",
+ "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.90.tgz",
+ "integrity": "sha512-iQmk+fThPq1ZTD2cFUu8xN6JLp9gFWnjs8auR6hmI6QQXoy6sSEh85uKcdkqpuEnkhhwQm4GSlKHOYfSCVp0Mw==",
+ "dependencies": {
+ "isomorphic.js": "^0.2.4"
+ },
+ "bin": {
+ "0gentesthtml": "bin/gentesthtml.js",
+ "0serve": "bin/0serve.js"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "GitHub Sponsors ❤",
+ "url": "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/sponsors/dmonad"
+ }
+ },
"playground/node_modules/rimraf": {
"version": "5.0.5",
"dev": true,
@@ -21583,6 +21592,34 @@
"url": "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/sponsors/isaacs"
}
},
+ "playground/node_modules/y-partykit": {
+ "version": "0.0.25",
+ "resolved": "https://registry.npmjs.org/y-partykit/-/y-partykit-0.0.25.tgz",
+ "integrity": "sha512-/EIL73TuYX6lYnxM4mb/kTTKllS1vNjBXk9KJXFwTXFrUqMo8hbJMqnE+glvBG2EDejEI06rk3jR50lpDB8Dqg==",
+ "dependencies": {
+ "lib0": "^0.2.89",
+ "lodash.debounce": "^4.0.8",
+ "react": "^18.2.0",
+ "y-protocols": "^1.0.6",
+ "yjs": "^13.6.12"
+ }
+ },
+ "playground/node_modules/yjs": {
+ "version": "13.6.14",
+ "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.14.tgz",
+ "integrity": "sha512-D+7KcUr0j+vBCUSKXXEWfA+bG4UQBviAwP3gYBhkstkgwy5+8diOPMx0iqLIOxNo/HxaREUimZRxqHGAHCL2BQ==",
+ "dependencies": {
+ "lib0": "^0.2.86"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">=8.0.0"
+ },
+ "funding": {
+ "type": "GitHub Sponsors ❤",
+ "url": "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/sponsors/dmonad"
+ }
+ },
"tests": {
"name": "@blocknote/tests",
"version": "0.11.2",
diff --git a/packages/core/src/editor/BlockNoteTipTapEditor.ts b/packages/core/src/editor/BlockNoteTipTapEditor.ts
index 789c5b44f9..8aee5c7f75 100644
--- a/packages/core/src/editor/BlockNoteTipTapEditor.ts
+++ b/packages/core/src/editor/BlockNoteTipTapEditor.ts
@@ -124,22 +124,25 @@ export class BlockNoteTipTapEditor extends TiptapEditor {
* Replace the default `createView` method with a custom one - which we call on mount
*/
private createViewAlternative() {
- this.view = new EditorView(this.options.element, {
- ...this.options.editorProps,
- // @ts-ignore
- dispatchTransaction: this.dispatchTransaction.bind(this),
- state: this.state,
- });
-
- // `editor.view` is not yet available at this time.
- // Therefore we will add all plugins and node views directly afterwards.
- const newState = this.state.reconfigure({
- plugins: this.extensionManager.plugins,
+ // Without queueMicrotask, custom IC / styles will give a React FlushSync error
+ queueMicrotask(() => {
+ this.view = new EditorView(this.options.element, {
+ ...this.options.editorProps,
+ // @ts-ignore
+ dispatchTransaction: this.dispatchTransaction.bind(this),
+ state: this.state,
+ });
+
+ // `editor.view` is not yet available at this time.
+ // Therefore we will add all plugins and node views directly afterwards.
+ const newState = this.state.reconfigure({
+ plugins: this.extensionManager.plugins,
+ });
+
+ this.view.updateState(newState);
+
+ this.createNodeViews();
});
-
- this.view.updateState(newState);
-
- this.createNodeViews();
}
/**
diff --git a/packages/dev-scripts/examples/genDocs.ts b/packages/dev-scripts/examples/genDocs.ts
index 205d019fbf..6fe505bcb5 100644
--- a/packages/dev-scripts/examples/genDocs.ts
+++ b/packages/dev-scripts/examples/genDocs.ts
@@ -170,6 +170,7 @@ async function generateExampleList(projects: Project[]) {
return {
text: project.title,
link: `/examples/${project.fullSlug}`,
+ author: project.config.author,
};
}),
};
diff --git a/packages/react/src/editor/EditorContent.tsx b/packages/react/src/editor/EditorContent.tsx
index 1610a0af94..7dedc6b178 100644
--- a/packages/react/src/editor/EditorContent.tsx
+++ b/packages/react/src/editor/EditorContent.tsx
@@ -43,7 +43,10 @@ export function EditorContent(props: {
});
},
};
- props.editor._tiptapEditor.createNodeViews();
+ // Without queueMicrotask, custom IC / styles will give a React FlushSync error
+ queueMicrotask(() => {
+ props.editor._tiptapEditor.createNodeViews();
+ });
return () => {
props.editor._tiptapEditor.contentComponent = null;
};