Skip to content

feat: Default image blocks #331

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 62 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
d218e3d
Made formatting toolbar buttons not show if they are not applicable
matthewlipski Aug 27, 2023
3f6210f
Made formatting toolbar placement change based on text alignment
matthewlipski Aug 27, 2023
132e7ce
Improved typing for blocks without inline content and made them selec…
matthewlipski Aug 27, 2023
df5c790
Updated default blocks with new typing
matthewlipski Aug 27, 2023
b137f43
Added image block (React implementation)
matthewlipski Aug 27, 2023
251c888
Added image upload and caption formatting toolbar buttons
matthewlipski Aug 27, 2023
70c7cb9
Added image slash menu item
matthewlipski Aug 27, 2023
5136c1f
Temporarily updated `App.tsx` to show image block
matthewlipski Aug 27, 2023
8cbbc50
Added placeholder `alt` attribute to image
matthewlipski Aug 27, 2023
99f7738
Added `destroy` function so vanilla custom blocks can clean ip betwee…
matthewlipski Aug 31, 2023
dc3b00c
Added vanilla image block
matthewlipski Aug 31, 2023
6d0e8b0
Added Uppy deps
matthewlipski Aug 31, 2023
9766343
Updated `ReplaceImageButton.tsx`
matthewlipski Aug 31, 2023
00fac4e
Small fix in `BlockColorsButton.tsx`
matthewlipski Aug 31, 2023
e514d61
Typing fix for hyperlink toolbar components
matthewlipski Aug 31, 2023
3812d3a
Created reusable components for link & caption components
matthewlipski Aug 31, 2023
a601989
Fixed import issue
matthewlipski Aug 31, 2023
9d729ab
Made image selection border also include caption
matthewlipski Aug 31, 2023
69a3e49
Added comment
matthewlipski Sep 1, 2023
f89c036
Added new hooks to clean up code
matthewlipski Sep 1, 2023
af8fc7c
Updated exports
matthewlipski Sep 1, 2023
b4904cb
Changed image replacing from Uppy to custom UI and removed `replacing…
matthewlipski Sep 4, 2023
de2fb45
Fixed z-index for UI elements
matthewlipski Sep 4, 2023
6bb9122
Changed image `width` prop to be in px
matthewlipski Sep 5, 2023
68c1275
Removed Uppy dependency
matthewlipski Sep 5, 2023
229c27f
Reverted `App.tsx`
matthewlipski Sep 5, 2023
d15673b
Removed React image block implementation
matthewlipski Sep 5, 2023
3ea172a
Fixed exports
matthewlipski Sep 5, 2023
4341c9f
Fixed image block imports
matthewlipski Sep 5, 2023
f637a9e
Small fixes to tests
matthewlipski Sep 5, 2023
f95f575
Changed image replacement to use image specific toolbar
matthewlipski Sep 7, 2023
59122ac
Made image toolbar open immediately after inserting an image using th…
matthewlipski Sep 11, 2023
8069460
Fixed replace image button having persistent `open` state
matthewlipski Sep 11, 2023
acf7172
`ImageToolbarPositioner.tsx` cleanup
matthewlipski Sep 11, 2023
f768c8b
Made image toolbar design more similar to Notion
matthewlipski Sep 13, 2023
38b60e6
Cleaned up block typing
matthewlipski Sep 18, 2023
d440c49
Implemented PR feedback
matthewlipski Sep 18, 2023
e1807db
Removed redundant z-index style from `ColorStyleButton`
matthewlipski Sep 18, 2023
0b2ace1
Made props able to be any primitive type and cleaned up test snapshots
matthewlipski Sep 19, 2023
4684547
Extracted image styles to CSS
matthewlipski Sep 19, 2023
3621393
Refactored `DefaultImageToolbar`
matthewlipski Sep 19, 2023
2d0789d
Added editor option for consumers to handle image uploads
matthewlipski Sep 19, 2023
7dd0717
Small `FormattingToolbarPositioner` refactor
matthewlipski Sep 20, 2023
42fe210
Fixed image slash menu item bug
matthewlipski Sep 20, 2023
9747206
Changed image toolbar to use tabs and fixed dark theme
matthewlipski Sep 21, 2023
585e4f4
Renamed image `src` prop to `url`
matthewlipski Sep 22, 2023
0566d49
Changed how image width is constrained to editor width
matthewlipski Sep 22, 2023
17bd6de
Updated default color names
matthewlipski Sep 22, 2023
8633697
Added loading overlay to the image toolbar while an image is being up…
matthewlipski Sep 22, 2023
82ba8a9
Fixed heading in block tyupe dropdown
matthewlipski Sep 26, 2023
35f7ded
small fixes (#346)
YousefED Sep 27, 2023
bf93d0c
Merge branch 'main' into image-block-new
matthewlipski Sep 27, 2023
0cebd9d
Small hook fix
matthewlipski Sep 27, 2023
cdb077b
Added image docs
matthewlipski Sep 28, 2023
fd1a6ef
Updated unit test snapshots
matthewlipski Sep 28, 2023
26e9dae
Added image e2e tests
matthewlipski Sep 29, 2023
c7b180e
Added error handling for image uploads
matthewlipski Oct 1, 2023
28ac8df
Renamed example image upload handler
matthewlipski Oct 1, 2023
eb54ac2
Added example image upload handler to docs home page
matthewlipski Oct 1, 2023
18e5b76
Small fixes
matthewlipski Oct 1, 2023
855d03f
Added test snapshots/screenshots
matthewlipski Oct 2, 2023
fecfcac
Improved e2e test reliability
matthewlipski Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/editor/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
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 };

Expand All @@ -16,6 +17,7 @@ function App() {
"data-test": "editor",
},
},
uploadFile: uploadToTmpFilesDotOrg_DEV_ONLY,
});

// Give tests a way to get prosemirror instance
Expand Down
28 changes: 26 additions & 2 deletions packages/core/src/BlockNoteEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
updateBlock,
} from "./api/blockManipulation/blockManipulation";
import {
HTMLToBlocks,
blocksToHTML,
blocksToMarkdown,
HTMLToBlocks,
markdownToBlocks,
} from "./api/formatConversions/formatConversions";
import {
Expand Down Expand Up @@ -44,6 +44,7 @@ import { getBlockInfoFromPos } from "./extensions/Blocks/helpers/getBlockInfoFro

import { FormattingToolbarProsemirrorPlugin } from "./extensions/FormattingToolbar/FormattingToolbarPlugin";
import { HyperlinkToolbarProsemirrorPlugin } from "./extensions/HyperlinkToolbar/HyperlinkToolbarPlugin";
import { ImageToolbarProsemirrorPlugin } from "./extensions/ImageToolbar/ImageToolbarPlugin";
import { SideMenuProsemirrorPlugin } from "./extensions/SideMenu/SideMenuPlugin";
import { BaseSlashMenuItem } from "./extensions/SlashMenu/BaseSlashMenuItem";
import { SlashMenuProsemirrorPlugin } from "./extensions/SlashMenu/SlashMenuPlugin";
Expand Down Expand Up @@ -106,6 +107,13 @@ export type BlockNoteEditorOptions<BSchema extends BlockSchema> = {
*/
blockSchema: BSchema;

/**
* A custom function to handle file uploads.
* @param file The file that should be uploaded.
* @returns The URL of the uploaded file.
*/
uploadFile: (file: File) => Promise<string>;

/**
* When enabled, allows for collaboration between multiple users.
*/
Expand Down Expand Up @@ -151,6 +159,9 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
public readonly formattingToolbar: FormattingToolbarProsemirrorPlugin<BSchema>;
public readonly slashMenu: SlashMenuProsemirrorPlugin<BSchema, any>;
public readonly hyperlinkToolbar: HyperlinkToolbarProsemirrorPlugin<BSchema>;
public readonly imageToolbar: ImageToolbarProsemirrorPlugin<BSchema>;

public readonly uploadFile: ((file: File) => Promise<string>) | undefined;

constructor(
private readonly options: Partial<BlockNoteEditorOptions<BSchema>> = {}
Expand Down Expand Up @@ -178,6 +189,7 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
getDefaultSlashMenuItems(newOptions.blockSchema)
);
this.hyperlinkToolbar = new HyperlinkToolbarProsemirrorPlugin(this);
this.imageToolbar = new ImageToolbarProsemirrorPlugin(this);

const extensions = getBlockNoteExtensions<BSchema>({
editor: this,
Expand All @@ -195,13 +207,16 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
this.formattingToolbar.plugin,
this.slashMenu.plugin,
this.hyperlinkToolbar.plugin,
this.imageToolbar.plugin,
];
},
});
extensions.push(blockNoteUIExtension);

this.schema = newOptions.blockSchema;

this.uploadFile = newOptions.uploadFile;

const initialContent =
newOptions.initialContent ||
(options.collaboration
Expand Down Expand Up @@ -460,6 +475,12 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
posBeforeNode + 2
)!;

// For blocks without inline content
if (contentNode.type.spec.content === "") {
this._tiptapEditor.commands.setNodeSelection(startPos);
return;
}

if (placement === "start") {
this._tiptapEditor.commands.setTextSelection(startPos + 1);
} else {
Expand All @@ -473,9 +494,12 @@ export class BlockNoteEditor<BSchema extends BlockSchema = DefaultBlockSchema> {
* Gets a snapshot of the current selection.
*/
public getSelection(): Selection<BSchema> | undefined {
// Either the TipTap selection is empty, or it's a node selection. In either
// case, it only spans one block, so we return undefined.
if (
this._tiptapEditor.state.selection.from ===
this._tiptapEditor.state.selection.to
this._tiptapEditor.state.selection.to ||
"node" in this._tiptapEditor.state.selection
) {
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Vitest Snapshot v1
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blocks 1`] = `
[
Expand All @@ -16,7 +16,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "2",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -33,7 +33,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "1",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -53,7 +53,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "4",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -70,7 +70,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "3",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand Down Expand Up @@ -106,7 +106,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "2",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand Down Expand Up @@ -142,7 +142,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "4",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -159,7 +159,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete multiple blo
"id": "3",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand Down Expand Up @@ -286,7 +286,7 @@ exports[`Insert, Update, & Delete Blocks > Insert, update, & delete single block
"id": "1",
"props": {
"backgroundColor": "default",
"level": "3",
"level": 3,
"textAlignment": "right",
"textColor": "default",
},
Expand Down Expand Up @@ -349,7 +349,7 @@ exports[`Inserting Blocks with Different Placements > Insert after existing bloc
"id": "2",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -366,7 +366,7 @@ exports[`Inserting Blocks with Different Placements > Insert after existing bloc
"id": "1",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -386,7 +386,7 @@ exports[`Inserting Blocks with Different Placements > Insert after existing bloc
"id": "4",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -403,7 +403,7 @@ exports[`Inserting Blocks with Different Placements > Insert after existing bloc
"id": "3",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand Down Expand Up @@ -439,7 +439,7 @@ exports[`Inserting Blocks with Different Placements > Insert before existing blo
"id": "2",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -456,7 +456,7 @@ exports[`Inserting Blocks with Different Placements > Insert before existing blo
"id": "1",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -476,7 +476,7 @@ exports[`Inserting Blocks with Different Placements > Insert before existing blo
"id": "4",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -493,7 +493,7 @@ exports[`Inserting Blocks with Different Placements > Insert before existing blo
"id": "3",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand Down Expand Up @@ -531,7 +531,7 @@ exports[`Inserting Blocks with Different Placements > Insert nested inside exist
"id": "2",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -548,7 +548,7 @@ exports[`Inserting Blocks with Different Placements > Insert nested inside exist
"id": "1",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -568,7 +568,7 @@ exports[`Inserting Blocks with Different Placements > Insert nested inside exist
"id": "4",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand All @@ -585,7 +585,7 @@ exports[`Inserting Blocks with Different Placements > Insert nested inside exist
"id": "3",
"props": {
"backgroundColor": "default",
"level": "2",
"level": 2,
"textAlignment": "left",
"textColor": "default",
},
Expand Down
19 changes: 8 additions & 11 deletions packages/core/src/api/blockManipulation/blockManipulation.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { Block, BlockNoteEditor, PartialBlock } from "../..";
import { DefaultBlockSchema } from "../../extensions/Blocks/api/defaultBlocks";

let editor: BlockNoteEditor;

Expand All @@ -15,13 +14,11 @@ function waitForEditor() {
});
}

let singleBlock: PartialBlock<DefaultBlockSchema>;
let singleBlock: PartialBlock;

let multipleBlocks: PartialBlock<DefaultBlockSchema>[];
let multipleBlocks: PartialBlock[];

let insert: (
placement: "before" | "nested" | "after"
) => Block<DefaultBlockSchema>[];
let insert: (placement: "before" | "nested" | "after") => Block[];

beforeEach(() => {
(window as Window & { __TEST_OPTIONS?: any }).__TEST_OPTIONS = {};
Expand All @@ -37,14 +34,14 @@ beforeEach(() => {
{
type: "heading",
props: {
level: "1",
level: 1,
},
content: "Heading 1",
children: [
{
type: "heading",
props: {
level: "1",
level: 1,
},
content: "Nested Heading 1",
},
Expand All @@ -53,14 +50,14 @@ beforeEach(() => {
{
type: "heading",
props: {
level: "2",
level: 2,
},
content: "Heading 2",
children: [
{
type: "heading",
props: {
level: "2",
level: 2,
},
content: "Nested Heading 2",
},
Expand Down Expand Up @@ -123,7 +120,7 @@ describe("Insert, Update, & Delete Blocks", () => {
type: "heading",
props: {
textAlignment: "right",
level: "3",
level: 3,
},
content: [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Vitest Snapshot v1
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Complex Block/HTML/Markdown Conversions > Convert complex blocks to HTML 1`] = `"<h1>Heading 1</h1><h2>Heading 2</h2><h3>Heading 3</h3><p><span data-text-color=\\"purple\\"><span data-background-color=\\"green\\">Paragraph</span></span></p><p>P<strong>ara</strong><em>grap</em>h</p><p>P<u>ara</u><s>grap</s>h</p><ul><li><p>Bullet List Item</p></li><li><p>Bullet List Item</p><ul><li><p>Bullet List Item</p><ul><li><p>Bullet List Item</p></li></ul><p>Paragraph</p><ol><li><p>Numbered List Item</p></li><li><p>Numbered List Item</p></li><li><p>Numbered List Item</p><ol><li><p>Numbered List Item</p></li></ol></li></ol><ul><li><p>Bullet List Item</p></li></ul></li><li><p>Bullet List Item</p></li></ul></li><li><p>Bullet List Item</p></li></ul>"`;

Expand Down Expand Up @@ -68,7 +68,7 @@ exports[`Non-Nested Block/HTML/Markdown Conversions > Convert non-nested HTML to
"id": "1",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand Down Expand Up @@ -142,7 +142,7 @@ exports[`Non-Nested Block/HTML/Markdown Conversions > Convert non-nested Markdow
"id": "1",
"props": {
"backgroundColor": "default",
"level": "1",
"level": 1,
"textAlignment": "left",
"textColor": "default",
},
Expand Down
Loading