Skip to content

Commit ed772f1

Browse files
feature: v0.10: tables, custom inline content, custom styles, better copy / paste handling (#426)
* feat: Custom block serialization (#257) * Added serialization for vanilla custom blocks * Added serialization for React custom blocks * Cleaned up serializer implementation - no longer uses function override * Revert "Cleaned up serializer implementation - no longer uses function override" This reverts commit b4f3fb6. * Removed comment * Added ability to set custom serialization and parse functions for custom blocks (parse still WIP) * Fixed build and most runtime issues * Added `react-dom` dependency * Added PoC copy/paste handling * Small changes & fixes * Added serialization tests * Changed copy/paste implementation * Small fix * Implemented PR feedback * Converted styles from modules to regular CSS * Implemented PR feedback * Updated serialization test snapshots * Updated serialization tests to use BlockNote API * Commented out custom block parsing code (out of scope for this PR) * Improved `nodeToBlock` typing * Small fixes * Fixed `destroy` function not getting passed to TipTap node view * Updated comment regarding clipboard issues * Major restructure of copy/paste code * Reduced code duplication for HTML serializer & exporter * Implemented PR feedback & cleaned up CSS class names * Updated serialization unit test snapshots * Changed `DOMOutputSpec` implementation for default blocks * Fixed some CSS issues * Implemented PR feedback * Reverted `nodeToBlock` typing * Made external HTML conversions no longer `async` and fixed Firefox clipboard reading * Fixed image test issues and small changes * Fixed remaining image test issues * Updated serialization unit test snapshots * Excluded `formatConversions` test * Fixed HTML export for custom blocks with inline content * Fixed duplicate `blockContainer` attributes getting added to custom blocks' `blockContent` nodes from color default props and changed `toExternalHTML` typing for React custom blocks * Added React serialization unit tests and extra vanilla tests * Updated image e2e snapshots * Small e2e test fix * Added comments * Fixed error when copying only nested blocks * refactor types for blocks (#412) * refactor types for blocks * remove unused comment * fix test * run tests on all branches * fix build * change BlockFromBlockConfig to Block * simplify customblockconfig * rename BlockImplementation to TiptapBlockImplementation * fix build * add comment * feat: tables (#413) * fix table types * add tablecontent * clean BNUpdateBlock * add partial inline content * add contentNodeToTableContent * first draft of tablehandles * implement table functions * fix styles * fix imports * create separate TableExtension * improve types * test some types * Fixed setting selection for table blocks * Fixed backspace deleting table if at start of cell * small code fixes * Implemented PR feedback * Improved table row/column drag & drop UX * Fixed table menus moving around, drag indicator flakiness, menu z-index issues, and drag preview * Implemented PR feedback * Implemented PR feedback * Fixed drag handles sometimes not showing * Fixed scrolling behaviour * Small fixes * Fixed table handles UI * Fixed remaining UX/UI issues * Removed redundant state from table handles plugin * Implemented table drag & drop logic * Added table enter handling * Small fix * feat: custom styles and custom inline content (#418) * wip custom styles * fix * fix tests * simplify PartialInlineContent * custom inline content * clean nodeconversions test * streamline tests * update tests * move schema files * add custom style test * inline content + tests * misc * clean imports * fix react tests * add react nodeconversions tests * move tests and add test for ReactStyles * fix react tests * basis of new examples * add react examples * fix bug * misc fixes * wip * clean * small cleanup * add comments * move funcs * fix tests * address PR feedback * fix inline content types * feat: HTML paste handling (#422) * refactor parse * fix parse-divsc * add test case * add extra test (that should be fixed) * readd markdown functions * fix tests * remove unused file * remove comments * add comment * nested list handling * add todos * added comment * use refs for blocks (#424) * use refs for blocks * update react htmlConversion test * Custom inline content and styles commands/copy & paste fixes (#425) * Fixed commands and internal copy/paste for inline content * Fixed internal copy/paste for styles * Small cleanup * fix some tests --------- Co-authored-by: yousefed <[email protected]> --------- Co-authored-by: Matthew Lipski <[email protected]> * use processSync --------- Co-authored-by: Matthew Lipski <[email protected]> * fix build --------- Co-authored-by: Matthew Lipski <[email protected]> --------- Co-authored-by: Matthew Lipski <[email protected]> Co-authored-by: Matthew Lipski <[email protected]> --------- Co-authored-by: Matthew Lipski <[email protected]> Co-authored-by: Matthew Lipski <[email protected]> --------- Co-authored-by: Yousef <[email protected]> * fix: change parse function to only return props * fix lint * add comment * Made block, inline content, and style content get parsed from `contentDOM` instead of `dom` * Small fixes * Fixed table enter handling * Updated unit tests * Fixed parsing error when `dom` is same as `contentDOM` (#429) * Fixed parsing error for styles/inline content where `dom` was the same as `contentDOM` * Updated react snapshots * Playground custom elements (#430) * Added playgrounds for vanilla blocks, React blocks, and vanilla inline content * fix renderHTML error * clean examples --------- Co-authored-by: yousefed <[email protected]> * Add markdown tests (#428) * update docs * add markdown tests * remove unused file * add missing space to mention tests * move and update playwright tests (#427) * move and update playwright tests * fix build * fix test setup * fix pw config * fix test command * Playwright refactor fixes (#436) * Fixed issues with most tests * Temporarily commented out failing unit test * Temporarily commented out failing unit test * Fixed remaining failing playwright tests * Re-added test that was causing issues * re-add tests * add pw-report * skip tests and edit css * revert style * add logs * fix unit tests --------- Co-authored-by: yousefed <[email protected]> --------- Co-authored-by: Matthew Lipski <[email protected]> * Block backspace key event at start of custom editable inline content (#435) * Fixed parsing error for styles/inline content where `dom` was the same as `contentDOM` * Updated react snapshots * Blocked backspace at start of custom editable inline content * add comment --------- Co-authored-by: yousefed <[email protected]> * fix empty table content * update comments * extract transformPasted * widen slashmenu typings * Updated docs for custom blocks and added tables (#442) --------- Co-authored-by: Matthew Lipski <[email protected]> Co-authored-by: Matthew Lipski <[email protected]>
1 parent a4e8f80 commit ed772f1

File tree

615 files changed

+16941
-5421
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

615 files changed

+16941
-5421
lines changed

.eslintrc.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
const typeScriptExtensions = [".ts", ".cts", ".mts", ".tsx"];
2+
3+
const allExtensions = [...typeScriptExtensions, ".js", ".jsx"];
4+
15
module.exports = {
26
root: true,
37
extends: [
@@ -8,6 +12,18 @@ module.exports = {
812
],
913
parser: "@typescript-eslint/parser",
1014
plugins: ["import", "@typescript-eslint"],
15+
settings: {
16+
"import/extensions": allExtensions,
17+
"import/external-module-folders": ["node_modules", "node_modules/@types"],
18+
"import/parsers": {
19+
"@typescript-eslint/parser": typeScriptExtensions,
20+
},
21+
"import/resolver": {
22+
node: {
23+
extensions: allExtensions,
24+
},
25+
},
26+
},
1127
rules: {
1228
curly: 1,
1329
"import/no-extraneous-dependencies": [
@@ -22,5 +38,20 @@ module.exports = {
2238
// would be nice to enable these rules later, but they are too noisy right now
2339
"@typescript-eslint/no-non-null-assertion": "off",
2440
"@typescript-eslint/no-explicit-any": "off",
41+
"@typescript-eslint/ban-ts-comment": "off",
42+
"import/no-cycle": "error",
43+
// doesn't work:
44+
// "import/no-restricted-paths": [
45+
// "error",
46+
// {
47+
// zones: [
48+
// {
49+
// target: "./src/**/*",
50+
// from: "./types/**/*",
51+
// message: "Import from this module to types is not allowed.",
52+
// },
53+
// ],
54+
// },
55+
// ],
2556
},
2657
};

.github/workflows/build.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ on:
55
- main
66
pull_request:
77
types: [opened, synchronize, reopened, edited]
8-
branches:
9-
- main
10-
- "project/**"
118

129
jobs:
1310
build:
@@ -70,13 +67,14 @@ jobs:
7067
run: npx playwright install --with-deps
7168

7269
- name: Run Playwright tests
70+
working-directory: ./tests
7371
run: npx playwright test
7472

7573
- uses: actions/upload-artifact@v3
7674
if: always()
7775
with:
7876
name: playwright-report
79-
path: playwright-report/
77+
path: tests/playwright-report/
8078
retention-days: 30
8179

8280
- name: Upload webpack stats artifact (editor)
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
// import logo from './logo.svg'
1+
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
22
import "@blocknote/core/style.css";
33
import { BlockNoteView, useBlockNote } from "@blocknote/react";
4-
import styles from "./App.module.css";
5-
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
64

75
type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any };
86

9-
function App() {
7+
export function App() {
108
const editor = useBlockNote({
11-
onEditorContentChange: (editor) => {
12-
console.log(editor.topLevelBlocks);
13-
},
149
domAttributes: {
1510
editor: {
16-
class: styles.editor,
11+
class: "editor",
1712
"data-test": "editor",
1813
},
1914
},
@@ -23,7 +18,7 @@ function App() {
2318
// Give tests a way to get prosemirror instance
2419
(window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor;
2520

26-
return <BlockNoteView editor={editor} />;
21+
return <BlockNoteView className="root" editor={editor} />;
2722
}
2823

2924
export default App;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
2+
import "@blocknote/core/style.css";
3+
import { BlockNoteView, useBlockNote } from "@blocknote/react";
4+
5+
import YPartyKitProvider from "y-partykit/provider";
6+
import * as Y from "yjs";
7+
8+
const doc = new Y.Doc();
9+
10+
const provider = new YPartyKitProvider(
11+
"blocknote-dev.yousefed.partykit.dev",
12+
// use a unique name as a "room" for your application:
13+
"your-project-name",
14+
doc
15+
);
16+
17+
type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any };
18+
19+
export function App() {
20+
const editor = useBlockNote({
21+
domAttributes: {
22+
editor: {
23+
class: "editor",
24+
"data-test": "editor",
25+
},
26+
},
27+
collaboration: {
28+
// The Yjs Provider responsible for transporting updates:
29+
provider,
30+
// Where to store BlockNote data in the Y.Doc:
31+
fragment: doc.getXmlFragment("document-storesss"),
32+
// Information (name and color) for this user:
33+
user: {
34+
name: "My Username",
35+
color: "#ff0000",
36+
},
37+
},
38+
uploadFile: uploadToTmpFilesDotOrg_DEV_ONLY,
39+
});
40+
41+
// Give tests a way to get prosemirror instance
42+
(window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor;
43+
44+
return <BlockNoteView className="root" editor={editor} />;
45+
}
46+
47+
export default App;
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { defaultBlockSpecs, defaultProps } from "@blocknote/core";
2+
import "@blocknote/core/style.css";
3+
import {
4+
BlockNoteView,
5+
createReactBlockSpec,
6+
useBlockNote,
7+
} from "@blocknote/react";
8+
import "../vanilla-custom-blocks/style.css";
9+
10+
type WindowWithProseMirror = Window & typeof globalThis & { ProseMirror: any };
11+
12+
// The types of alerts that users can choose from
13+
const alertTypes = {
14+
warning: {
15+
icon: "⚠️",
16+
color: "#e69819",
17+
backgroundColor: "#fff6e6",
18+
},
19+
error: {
20+
icon: "⛔",
21+
color: "#d80d0d",
22+
backgroundColor: "#ffe6e6",
23+
},
24+
info: {
25+
icon: "ℹ️",
26+
color: "#507aff",
27+
backgroundColor: "#e6ebff",
28+
},
29+
success: {
30+
icon: "✅",
31+
color: "#0bc10b",
32+
backgroundColor: "#e6ffe6",
33+
},
34+
};
35+
36+
export const alertBlock = createReactBlockSpec(
37+
{
38+
type: "alert",
39+
propSchema: {
40+
textAlignment: defaultProps.textAlignment,
41+
textColor: defaultProps.textColor,
42+
type: {
43+
default: "warning" as const,
44+
values: ["warning", "error", "info", "success"] as const,
45+
},
46+
},
47+
content: "inline",
48+
},
49+
{
50+
render: (props) => (
51+
<div
52+
className={"alert"}
53+
style={{
54+
backgroundColor: alertTypes[props.block.props.type].backgroundColor,
55+
}}>
56+
<select
57+
contentEditable={false}
58+
value={props.block.props.type}
59+
onChange={(event) => {
60+
props.editor.updateBlock(props.block, {
61+
type: "alert",
62+
props: { type: event.target.value as keyof typeof alertTypes },
63+
});
64+
}}>
65+
<option value="warning">{alertTypes["warning"].icon}</option>
66+
<option value="error">{alertTypes["error"].icon}</option>
67+
<option value="info">{alertTypes["info"].icon}</option>
68+
<option value="success">{alertTypes["success"].icon}</option>
69+
</select>
70+
<div className={"inline-content"} ref={props.contentRef} />
71+
</div>
72+
),
73+
}
74+
);
75+
76+
const simpleImageBlock = createReactBlockSpec(
77+
{
78+
type: "simpleImage",
79+
propSchema: {
80+
src: {
81+
default:
82+
"https://www.pulsecarshalton.co.uk/wp-content/uploads/2016/08/jk-placeholder-image.jpg",
83+
},
84+
},
85+
content: "none",
86+
},
87+
{
88+
render: (props) => (
89+
<img
90+
className={"simple-image"}
91+
src={props.block.props.src}
92+
alt="placeholder"
93+
/>
94+
),
95+
}
96+
);
97+
98+
export const bracketsParagraphBlock = createReactBlockSpec(
99+
{
100+
type: "bracketsParagraph",
101+
content: "inline",
102+
propSchema: {
103+
...defaultProps,
104+
},
105+
},
106+
{
107+
render: (props) => (
108+
<div className={"brackets-paragraph"}>
109+
<div contentEditable={"false"}>{"["}</div>
110+
<span contentEditable={"false"}>{"{"}</span>
111+
<div className={"inline-content"} ref={props.contentRef} />
112+
<span contentEditable={"false"}>{"}"}</span>
113+
<div contentEditable={"false"}>{"]"}</div>
114+
</div>
115+
),
116+
}
117+
);
118+
119+
export function ReactCustomBlocks() {
120+
const editor = useBlockNote({
121+
domAttributes: {
122+
editor: {
123+
class: "editor",
124+
"data-test": "editor",
125+
},
126+
},
127+
blockSpecs: {
128+
...defaultBlockSpecs,
129+
alert: alertBlock,
130+
simpleImage: simpleImageBlock,
131+
bracketsParagraph: bracketsParagraphBlock,
132+
},
133+
initialContent: [
134+
{
135+
type: "alert",
136+
props: {
137+
type: "success",
138+
},
139+
content: "Alert",
140+
},
141+
{
142+
type: "simpleImage",
143+
props: {
144+
src: "https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
145+
},
146+
},
147+
{
148+
type: "bracketsParagraph",
149+
content: "Brackets Paragraph",
150+
},
151+
],
152+
});
153+
154+
// Give tests a way to get prosemirror instance
155+
(window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor;
156+
157+
return <BlockNoteView className="root" editor={editor} />;
158+
}

0 commit comments

Comments
 (0)