Skip to content

fix: backwards-compat for _extensions #1708

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 8 commits into from
May 23, 2025
60 changes: 0 additions & 60 deletions .eslintrc.js

This file was deleted.

42 changes: 42 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"root": true,
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"react-app",
"react-app/jest"
],
"parser": "@typescript-eslint/parser",
"plugins": ["import", "@typescript-eslint"],
"settings": {
"import/extensions": [".ts", ".cts", ".mts", ".tsx", ".js", ".jsx"],
"import/external-module-folders": ["node_modules", "node_modules/@types"],
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".cts", ".mts", ".tsx"]
},
"import/resolver": {
"node": {
"extensions": [".ts", ".cts", ".mts", ".tsx", ".js", ".jsx"]
}
}
},
"ignorePatterns": ["**/ui/*"],
"rules": {
"no-console": "error",
"curly": 1,
"import/extensions": ["error", "always", { "ignorePackages": true }],
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": true,
"peerDependencies": true,
"optionalDependencies": false,
"bundledDependencies": false
}
],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-ts-comment": "off",
"import/no-cycle": "error"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"tags": ["Extension"],
"pro": true,
"dependencies": {
"@tiptap/core": "^2"
"@tiptap/core": "^2.12.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@blocknote/shadcn": "latest",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@tiptap/core": "^2"
"@tiptap/core": "^2.12.0"
},
"devDependencies": {
"@types/react": "^18.0.25",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "root",
"type": "module",
"devDependencies": {
"@nx/js": "20.6.4",
"@typescript-eslint/eslint-plugin": "^5.5.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/ariakit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
},
"eslintConfig": {
"extends": [
"../../.eslintrc.js"
"../../.eslintrc.json"
]
}
}
2 changes: 1 addition & 1 deletion packages/code-block/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
},
"eslintConfig": {
"extends": [
"../../.eslintrc.js"
"../../.eslintrc.json"
]
},
"gitHead": "37614ab348dcc7faa830a9a88437b37197a2162d"
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
},
"eslintConfig": {
"extends": [
"../../.eslintrc.js"
"../../.eslintrc.json"
]
},
"gitHead": "37614ab348dcc7faa830a9a88437b37197a2162d"
Expand Down
48 changes: 41 additions & 7 deletions packages/core/src/editor/BlockNoteEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,14 @@ export type BlockNoteEditorOptions<
*
* @deprecated, should use `extensions` instead
*/
_extensions: Record<string, BlockNoteExtension | BlockNoteExtensionFactory>;
_extensions: Record<
string,
| { plugin: Plugin; priority?: number }
| ((editor: BlockNoteEditor<any, any, any>) => {
plugin: Plugin;
priority?: number;
})
>;

/**
* Register
Expand Down Expand Up @@ -630,17 +637,44 @@ export class BlockNoteEditor<
// factory
ext = ext(this);
}
const key = (ext.constructor as any).name();
const key = (ext.constructor as any).key();
if (!key) {
throw new Error(
`Extension ${ext.constructor.name} does not have a key method`,
);
}
if (this.extensions[key]) {
throw new Error(
`Extension ${ext.constructor.name} already exists with key ${key}`,
);
}
this.extensions[key] = ext;
}

// (when passed in via the deprecated `_extensions` option)
Object.entries(newOptions._extensions || {}).forEach(([key, ext]) => {
if (typeof ext === "function") {
// factory
ext = ext(this);
// eslint-disable-next-line @typescript-eslint/no-this-alias
const editor = this;

const instance = typeof ext === "function" ? ext(editor) : ext;
if (!("plugin" in instance)) {
// Assume it is an Extension/Mark/Node
this.extensions[key] = instance;
return;
}
this.extensions[key] = ext;

this.extensions[key] = new (class extends BlockNoteExtension {
public static key() {
return key;
}
constructor() {
super();
this.addProsemirrorPlugin(instance.plugin);
}
public get priority() {
return instance.priority;
}
})();
});

this.formattingToolbar = this.extensions["formattingToolbar"] as any;
Expand Down Expand Up @@ -901,7 +935,7 @@ export class BlockNoteEditor<
*/
public extension<T extends BlockNoteExtension>(
ext: { new (...args: any[]): T } & typeof BlockNoteExtension,
key = ext.name(),
key = ext.key(),
): T {
const extension = this.extensions[key] as T;
if (!extension) {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/editor/BlockNoteExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { EventEmitter } from "../util/EventEmitter.js";
export abstract class BlockNoteExtension<
TEvent extends Record<string, any> = any,
> extends EventEmitter<TEvent> {
public static name(): string {
throw new Error("You must implement the name method in your extension");
public static key(): string {
throw new Error("You must implement the key method in your extension");
}

protected addProsemirrorPlugin(plugin: Plugin) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/extensions/Collaboration/CursorPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type CollaborationUser = {
};

export class CursorPlugin extends BlockNoteExtension {
public static name() {
public static key() {
return "yCursorPlugin";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
export class ForkYDocPlugin extends BlockNoteExtension<{
forked: boolean;
}> {
public static name() {
public static key() {
return "ForkYDocPlugin";
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/extensions/Collaboration/SyncPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type * as Y from "yjs";
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";

export class SyncPlugin extends BlockNoteExtension {
public static name() {
public static key() {
return "ySyncPlugin";
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/extensions/Collaboration/UndoPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { yUndoPlugin } from "y-prosemirror";
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";

export class UndoPlugin extends BlockNoteExtension {
public static name() {
public static key() {
return "yUndoPlugin";
}

Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/extensions/Comments/CommentsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ function getUpdatedThreadPositions(doc: Node, markType: string) {
}

export class CommentsPlugin extends BlockNoteExtension {
public static key() {
return "comments";
}

public readonly userStore: UserStore<User>;

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/extensions/FilePanel/FilePanelPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ export class FilePanelProsemirrorPlugin<
I extends InlineContentSchema,
S extends StyleSchema,
> extends BlockNoteExtension {
public static key() {
return "filePanel";
}

private view: FilePanelView<I, S> | undefined;

constructor(editor: BlockNoteEditor<Record<string, FileBlockConfig>, I, S>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ export const formattingToolbarPluginKey = new PluginKey(
);

export class FormattingToolbarProsemirrorPlugin extends BlockNoteExtension {
public static key() {
return "formattingToolbar";
}

private view: FormattingToolbarView | undefined;

constructor(editor: BlockNoteEditor<any, any, any>) {
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/extensions/LinkToolbar/LinkToolbarPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ export class LinkToolbarProsemirrorPlugin<
I extends InlineContentSchema,
S extends StyleSchema,
> extends BlockNoteExtension {
public static key() {
return "linkToolbar";
}

private view: LinkToolbarView | undefined;

constructor(editor: BlockNoteEditor<BSchema, I, S>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const PLUGIN_KEY = new PluginKey("node-selection-keyboard");
// keystrokes, this brings us most of the way to Notion's UX without much added
// complexity.
export class NodeSelectionKeyboardPlugin extends BlockNoteExtension {
public static key() {
return "nodeSelectionKeyboard";
}

constructor() {
super();
this.addProsemirrorPlugin(
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/extensions/Placeholder/PlaceholderPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
const PLUGIN_KEY = new PluginKey(`blocknote-placeholder`);

export class PlaceholderPlugin extends BlockNoteExtension {
public static key() {
return "placeholder";
}

constructor(
editor: BlockNoteEditor<any, any, any>,
placeholders: Record<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const nodeAttributes: Record<string, string> = {
* Solution: When attributes change on a node, this plugin sets a data-* attribute with the "previous" value. This way we can still use CSS transitions. (See block.module.css)
*/
export class PreviousBlockTypePlugin extends BlockNoteExtension {
public static key() {
return "previousBlockType";
}

constructor() {
super();
let timeout: ReturnType<typeof setTimeout>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const PLUGIN_KEY = new PluginKey(`blocknote-show-selection`);
* text editor is not focused.
*/
export class ShowSelectionPlugin extends BlockNoteExtension {
public static key() {
return "showSelection";
}

private enabled = false;

public constructor(private readonly editor: BlockNoteEditor<any, any, any>) {
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/extensions/SideMenu/SideMenuPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,10 @@ export class SideMenuProsemirrorPlugin<
I extends InlineContentSchema,
S extends StyleSchema,
> extends BlockNoteExtension {
public static key() {
return "sideMenu";
}

public view: SideMenuView<BSchema, I, S> | undefined;

constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ export class SuggestionMenuProseMirrorPlugin<
I extends InlineContentSchema,
S extends StyleSchema,
> extends BlockNoteExtension {
public static key() {
return "suggestionMenu";
}

private view: SuggestionMenuView<BSchema, I, S> | undefined;
private triggerCharacters: string[] = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,10 @@ export class TableHandlesProsemirrorPlugin<
I extends InlineContentSchema,
S extends StyleSchema,
> extends BlockNoteExtension {
public static key() {
return "tableHandles";
}

private view: TableHandlesView<I, S> | undefined;

constructor(
Expand Down
Loading
Loading