Skip to content

feature: v0.10: tables, custom inline content, custom styles, better copy / paste handling #426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
01c9ef6
feat: Custom block serialization (#257)
matthewlipski Nov 29, 2023
291f623
fix: change parse function to only return props
YousefED Nov 29, 2023
39e1421
fix lint
YousefED Nov 29, 2023
f000b44
add comment
YousefED Nov 29, 2023
6bc8d3e
Made block, inline content, and style content get parsed from `conten…
matthewlipski Nov 29, 2023
b85918c
Merge remote-tracking branch 'origin/refactor/tables-customelements-c…
matthewlipski Nov 29, 2023
2bf6ed0
Small fixes
matthewlipski Nov 29, 2023
a186d3b
Fixed table enter handling
matthewlipski Nov 29, 2023
4b59185
Updated unit tests
matthewlipski Nov 29, 2023
b28c2c9
Fixed parsing error when `dom` is same as `contentDOM` (#429)
matthewlipski Nov 29, 2023
a52ffce
Playground custom elements (#430)
matthewlipski Nov 30, 2023
b46a847
Add markdown tests (#428)
YousefED Nov 30, 2023
2b5c0fa
move and update playwright tests (#427)
YousefED Dec 1, 2023
9d0d124
Block backspace key event at start of custom editable inline content …
matthewlipski Dec 1, 2023
05cd699
fix empty table content
YousefED Dec 1, 2023
fc61e25
update comments
YousefED Dec 1, 2023
5a48db4
extract transformPasted
YousefED Dec 1, 2023
6e7d43a
widen slashmenu typings
YousefED Dec 1, 2023
8047945
Updated docs for custom blocks and added tables (#442)
matthewlipski Dec 4, 2023
40eba12
Merge remote-tracking branch 'TypeCellOS/main' into refactor/tables-c…
YousefED Dec 4, 2023
d67bce5
Playground vanilla styles & non-editable custom blocks (#438)
matthewlipski Dec 4, 2023
732cbba
Merge remote-tracking branch 'TypeCellOS/main' into refactor/tables-c…
YousefED Dec 4, 2023
e320915
chore: remove lodash (#448)
YousefED Dec 4, 2023
d59879d
refactor: update directory structure and imports (#447)
YousefED Dec 4, 2023
0650d02
fix source map error
YousefED Dec 4, 2023
c5fc530
Merge branch 'refactor/tables-customelements-copypaste' of github.com…
YousefED Dec 4, 2023
fb7e459
Added tests for parsing complex docs from Notion and Google Docs (#449)
matthewlipski Dec 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 31 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
const typeScriptExtensions = [".ts", ".cts", ".mts", ".tsx"];

const allExtensions = [...typeScriptExtensions, ".js", ".jsx"];

module.exports = {
root: true,
extends: [
Expand All @@ -8,6 +12,18 @@ module.exports = {
],
parser: "@typescript-eslint/parser",
plugins: ["import", "@typescript-eslint"],
settings: {
"import/extensions": allExtensions,
"import/external-module-folders": ["node_modules", "node_modules/@types"],
"import/parsers": {
"@typescript-eslint/parser": typeScriptExtensions,
},
"import/resolver": {
node: {
extensions: allExtensions,
},
},
},
rules: {
curly: 1,
"import/no-extraneous-dependencies": [
Expand All @@ -22,5 +38,20 @@ module.exports = {
// would be nice to enable these rules later, but they are too noisy right now
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-ts-comment": "off",
"import/no-cycle": "error",
// doesn't work:
// "import/no-restricted-paths": [
// "error",
// {
// zones: [
// {
// target: "./src/**/*",
// from: "./types/**/*",
// message: "Import from this module to types is not allowed.",
// },
// ],
// },
// ],
},
};
6 changes: 2 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ on:
- main
pull_request:
types: [opened, synchronize, reopened, edited]
branches:
- main
- "project/**"

jobs:
build:
Expand Down Expand Up @@ -70,13 +67,14 @@ jobs:
run: npx playwright install --with-deps

- name: Run Playwright tests
working-directory: ./tests
run: npx playwright test

- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
path: tests/playwright-report/
retention-days: 30

- name: Upload webpack stats artifact (editor)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
// import logo from './logo.svg'
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
import "@blocknote/core/style.css";
import { BlockNoteView, useBlockNote } from "@blocknote/react";
import styles from "./App.module.css";
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";

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

function App() {
export function App() {
const editor = useBlockNote({
onEditorContentChange: (editor) => {
console.log(editor.topLevelBlocks);
},
domAttributes: {
editor: {
class: styles.editor,
class: "editor",
"data-test": "editor",
},
},
Expand All @@ -23,7 +18,7 @@ function App() {
// Give tests a way to get prosemirror instance
(window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor;

return <BlockNoteView editor={editor} />;
return <BlockNoteView className="root" editor={editor} />;
}

export default App;
47 changes: 47 additions & 0 deletions examples/editor/examples/collaboration/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { uploadToTmpFilesDotOrg_DEV_ONLY } from "@blocknote/core";
import "@blocknote/core/style.css";
import { BlockNoteView, useBlockNote } from "@blocknote/react";

import YPartyKitProvider from "y-partykit/provider";
import * as Y from "yjs";

const doc = new Y.Doc();

const provider = new YPartyKitProvider(
"blocknote-dev.yousefed.partykit.dev",
// use a unique name as a "room" for your application:
"your-project-name",
doc
);

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

export function App() {
const editor = useBlockNote({
domAttributes: {
editor: {
class: "editor",
"data-test": "editor",
},
},
collaboration: {
// The Yjs Provider responsible for transporting updates:
provider,
// Where to store BlockNote data in the Y.Doc:
fragment: doc.getXmlFragment("document-storesss"),
// Information (name and color) for this user:
user: {
name: "My Username",
color: "#ff0000",
},
},
uploadFile: uploadToTmpFilesDotOrg_DEV_ONLY,
});

// Give tests a way to get prosemirror instance
(window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor;

return <BlockNoteView className="root" editor={editor} />;
}

export default App;
158 changes: 158 additions & 0 deletions examples/editor/examples/react-custom-blocks/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { defaultBlockSpecs, defaultProps } from "@blocknote/core";
import "@blocknote/core/style.css";
import {
BlockNoteView,
createReactBlockSpec,
useBlockNote,
} from "@blocknote/react";
import "../vanilla-custom-blocks/style.css";

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

// The types of alerts that users can choose from
const alertTypes = {
warning: {
icon: "⚠️",
color: "#e69819",
backgroundColor: "#fff6e6",
},
error: {
icon: "⛔",
color: "#d80d0d",
backgroundColor: "#ffe6e6",
},
info: {
icon: "ℹ️",
color: "#507aff",
backgroundColor: "#e6ebff",
},
success: {
icon: "✅",
color: "#0bc10b",
backgroundColor: "#e6ffe6",
},
};

export const alertBlock = createReactBlockSpec(
{
type: "alert",
propSchema: {
textAlignment: defaultProps.textAlignment,
textColor: defaultProps.textColor,
type: {
default: "warning" as const,
values: ["warning", "error", "info", "success"] as const,
},
},
content: "inline",
},
{
render: (props) => (
<div
className={"alert"}
style={{
backgroundColor: alertTypes[props.block.props.type].backgroundColor,
}}>
<select
contentEditable={false}
value={props.block.props.type}
onChange={(event) => {
props.editor.updateBlock(props.block, {
type: "alert",
props: { type: event.target.value as keyof typeof alertTypes },
});
}}>
<option value="warning">{alertTypes["warning"].icon}</option>
<option value="error">{alertTypes["error"].icon}</option>
<option value="info">{alertTypes["info"].icon}</option>
<option value="success">{alertTypes["success"].icon}</option>
</select>
<div className={"inline-content"} ref={props.contentRef} />
</div>
),
}
);

const simpleImageBlock = createReactBlockSpec(
{
type: "simpleImage",
propSchema: {
src: {
default:
"https://www.pulsecarshalton.co.uk/wp-content/uploads/2016/08/jk-placeholder-image.jpg",
},
},
content: "none",
},
{
render: (props) => (
<img
className={"simple-image"}
src={props.block.props.src}
alt="placeholder"
/>
),
}
);

export const bracketsParagraphBlock = createReactBlockSpec(
{
type: "bracketsParagraph",
content: "inline",
propSchema: {
...defaultProps,
},
},
{
render: (props) => (
<div className={"brackets-paragraph"}>
<div contentEditable={"false"}>{"["}</div>
<span contentEditable={"false"}>{"{"}</span>
<div className={"inline-content"} ref={props.contentRef} />
<span contentEditable={"false"}>{"}"}</span>
<div contentEditable={"false"}>{"]"}</div>
</div>
),
}
);

export function ReactCustomBlocks() {
const editor = useBlockNote({
domAttributes: {
editor: {
class: "editor",
"data-test": "editor",
},
},
blockSpecs: {
...defaultBlockSpecs,
alert: alertBlock,
simpleImage: simpleImageBlock,
bracketsParagraph: bracketsParagraphBlock,
},
initialContent: [
{
type: "alert",
props: {
type: "success",
},
content: "Alert",
},
{
type: "simpleImage",
props: {
src: "https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
},
},
{
type: "bracketsParagraph",
content: "Brackets Paragraph",
},
],
});

// Give tests a way to get prosemirror instance
(window as WindowWithProseMirror).ProseMirror = editor?._tiptapEditor;

return <BlockNoteView className="root" editor={editor} />;
}
Loading