Skip to content

Commit 4d44c84

Browse files
committed
Changed formatting toolbar props to use BlockNoteEditor
1 parent 7aa833e commit 4d44c84

File tree

20 files changed

+539
-488
lines changed

20 files changed

+539
-488
lines changed

examples/vanilla/src/ui/formattingToolbarFactory.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ export const formattingToolbarFactory: FormattingToolbarFactory = (
1414
container.style.padding = "10px";
1515
container.style.opacity = "0.8";
1616
const boldBtn = createButton("set bold", () => {
17-
staticParams.toggleBold();
17+
staticParams.editor.toggleStyles({ bold: true });
1818
});
1919
container.appendChild(boldBtn);
2020

2121
const linkBtn = createButton("set link", () => {
22-
staticParams.setHyperlink("https://www.google.com");
22+
staticParams.editor.createLink("https://www.google.com");
2323
});
2424

2525
container.appendChild(boldBtn);
@@ -34,7 +34,8 @@ export const formattingToolbarFactory: FormattingToolbarFactory = (
3434
container.style.display = "block";
3535
}
3636

37-
boldBtn.text = params.boldIsActive ? "unset bold" : "set bold";
37+
boldBtn.text =
38+
"bold" in params.editor.getActiveStyles() ? "unset bold" : "set bold";
3839
container.style.top = params.referenceRect.y + "px";
3940
container.style.left = params.referenceRect.x + "px";
4041
},

packages/core/src/BlockNoteEditor.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ import {
2323
BlockIdentifier,
2424
PartialBlock,
2525
} from "./extensions/Blocks/api/blockTypes";
26+
import {
27+
ColorStyle,
28+
Styles,
29+
ToggledStyle,
30+
} from "./extensions/Blocks/api/inlineContentTypes";
2631
import { TextCursorPosition } from "./extensions/Blocks/api/cursorPositionTypes";
2732
import { getBlockInfoFromPos } from "./extensions/Blocks/helpers/getBlockInfoFromPos";
2833
import {
@@ -60,6 +65,10 @@ export class BlockNoteEditor {
6065
return this._tiptapEditor.view.dom as HTMLDivElement;
6166
}
6267

68+
public focus() {
69+
this._tiptapEditor.view.focus();
70+
}
71+
6372
constructor(options: Partial<BlockNoteEditorOptions> = {}) {
6473
const blockNoteExtensions = getBlockNoteExtensions({
6574
editor: this,
@@ -299,6 +308,135 @@ export class BlockNoteEditor {
299308
replaceBlocks(blocksToRemove, blocksToInsert, this._tiptapEditor);
300309
}
301310

311+
public getActiveStyles() {
312+
const styles: Styles = {};
313+
const marks = this._tiptapEditor.state.selection.$to.marks();
314+
console.log(marks);
315+
316+
const toggleStyles = new Set<ToggledStyle>([
317+
"bold",
318+
"italic",
319+
"underline",
320+
"strike",
321+
]);
322+
const colorStyles = new Set<ColorStyle>(["textColor", "backgroundColor"]);
323+
324+
for (const mark of marks) {
325+
if (toggleStyles.has(mark.type.name as ToggledStyle)) {
326+
styles[mark.type.name as ToggledStyle] = true;
327+
} else if (colorStyles.has(mark.type.name as ColorStyle)) {
328+
styles[mark.type.name as ColorStyle] = mark.attrs.color;
329+
}
330+
}
331+
332+
return styles;
333+
}
334+
335+
public addStyles(styles: Styles) {
336+
const toggleStyles = new Set<ToggledStyle>([
337+
"bold",
338+
"italic",
339+
"underline",
340+
"strike",
341+
]);
342+
const colorStyles = new Set<ColorStyle>(["textColor", "backgroundColor"]);
343+
344+
this._tiptapEditor.view.focus();
345+
346+
for (const [style, value] of Object.entries(styles)) {
347+
if (toggleStyles.has(style as ToggledStyle)) {
348+
this._tiptapEditor.commands.setMark(style);
349+
} else if (colorStyles.has(style as ColorStyle)) {
350+
this._tiptapEditor.commands.setMark(style, { color: value });
351+
}
352+
}
353+
}
354+
355+
public removeStyles(styles: Styles) {
356+
this._tiptapEditor.view.focus();
357+
358+
for (const style of Object.keys(styles)) {
359+
this._tiptapEditor.commands.unsetMark(style);
360+
}
361+
}
362+
363+
public toggleStyles(styles: Styles) {
364+
const toggleStyles = new Set<ToggledStyle>([
365+
"bold",
366+
"italic",
367+
"underline",
368+
"strike",
369+
]);
370+
const colorStyles = new Set<ColorStyle>(["textColor", "backgroundColor"]);
371+
372+
this._tiptapEditor.view.focus();
373+
374+
for (const [style, value] of Object.entries(styles)) {
375+
if (toggleStyles.has(style as ToggledStyle)) {
376+
this._tiptapEditor.commands.toggleMark(style);
377+
} else if (colorStyles.has(style as ColorStyle)) {
378+
this._tiptapEditor.commands.toggleMark(style, { color: value });
379+
}
380+
}
381+
}
382+
383+
public getActiveLink() {
384+
const url = this._tiptapEditor.getAttributes("link").href;
385+
// TODO: Does this make sense? Shouldn't it get the actual link text?
386+
const text = this._tiptapEditor.state.doc.textBetween(
387+
this._tiptapEditor.state.selection.from,
388+
this._tiptapEditor.state.selection.to
389+
);
390+
391+
return { text: text, url: url };
392+
}
393+
394+
public createLink(url: string, text?: string) {
395+
if (url === "") {
396+
return;
397+
}
398+
399+
let { from, to } = this._tiptapEditor.state.selection;
400+
401+
if (!text) {
402+
text = this._tiptapEditor.state.doc.textBetween(from, to);
403+
}
404+
405+
const mark = this._tiptapEditor.schema.mark("link", { href: url });
406+
407+
this._tiptapEditor.view.dispatch(
408+
this._tiptapEditor.view.state.tr
409+
.insertText(text, from, to)
410+
.addMark(from, from + text.length, mark)
411+
);
412+
}
413+
414+
public canNestBlock() {
415+
const { startPos, depth } = getBlockInfoFromPos(
416+
this._tiptapEditor.state.doc,
417+
this._tiptapEditor.state.selection.from
418+
)!;
419+
420+
return this._tiptapEditor.state.doc.resolve(startPos).index(depth - 1) > 0;
421+
}
422+
423+
public nestBlock() {
424+
this._tiptapEditor.commands.sinkListItem("blockContainer");
425+
}
426+
427+
public canUnnestBlock() {
428+
const { depth } = getBlockInfoFromPos(
429+
this._tiptapEditor.state.doc,
430+
this._tiptapEditor.state.selection.from
431+
)!;
432+
433+
return depth > 2;
434+
}
435+
436+
public unnestBlock() {
437+
this._tiptapEditor.commands.liftListItem("blockContainer");
438+
}
439+
302440
/**
303441
* Serializes blocks into an HTML string. To better conform to HTML standards, children of blocks which aren't list
304442
* items are un-nested in the output HTML.

packages/core/src/api/nodeConversions/nodeConversions.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@ import {
66
PartialBlock,
77
} from "../../extensions/Blocks/api/blockTypes";
88
import {
9-
ColorStyles,
9+
ColorStyle,
1010
InlineContent,
1111
Link,
1212
PartialInlineContent,
1313
PartialLink,
1414
StyledText,
1515
Styles,
16-
ToggledStyles,
16+
ToggledStyle,
1717
} from "../../extensions/Blocks/api/inlineContentTypes";
1818
import { getBlockInfoFromPos } from "../../extensions/Blocks/helpers/getBlockInfoFromPos";
1919
import UniqueID from "../../extensions/UniqueID/UniqueID";
2020
import { UnreachableCaseError } from "../../shared/utils";
2121

22-
const toggleStyles = new Set<ToggledStyles>([
22+
const toggleStyles = new Set<ToggledStyle>([
2323
"bold",
2424
"italic",
2525
"underline",
2626
"strike",
2727
]);
28-
const colorStyles = new Set<ColorStyles>(["textColor", "backgroundColor"]);
28+
const colorStyles = new Set<ColorStyle>(["textColor", "backgroundColor"]);
2929

3030
/**
3131
* Convert a StyledText inline element to a
@@ -35,9 +35,9 @@ function styledTextToNode(styledText: StyledText, schema: Schema): Node {
3535
const marks: Mark[] = [];
3636

3737
for (const [style, value] of Object.entries(styledText.styles)) {
38-
if (toggleStyles.has(style as ToggledStyles)) {
38+
if (toggleStyles.has(style as ToggledStyle)) {
3939
marks.push(schema.mark(style));
40-
} else if (colorStyles.has(style as ColorStyles)) {
40+
} else if (colorStyles.has(style as ColorStyle)) {
4141
marks.push(schema.mark(style, { color: value }));
4242
}
4343
}
@@ -167,10 +167,10 @@ function contentNodeToInlineContent(contentNode: Node) {
167167
for (const mark of node.marks) {
168168
if (mark.type.name === "link") {
169169
linkMark = mark;
170-
} else if (toggleStyles.has(mark.type.name as ToggledStyles)) {
171-
styles[mark.type.name as ToggledStyles] = true;
172-
} else if (colorStyles.has(mark.type.name as ColorStyles)) {
173-
styles[mark.type.name as ColorStyles] = mark.attrs.color;
170+
} else if (toggleStyles.has(mark.type.name as ToggledStyle)) {
171+
styles[mark.type.name as ToggledStyle] = true;
172+
} else if (colorStyles.has(mark.type.name as ColorStyle)) {
173+
styles[mark.type.name as ColorStyle] = mark.attrs.color;
174174
} else {
175175
throw Error("Mark is of an unrecognized type: " + mark.type.name);
176176
}

packages/core/src/extensions/Blocks/api/inlineContentTypes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ export type Styles = {
77
backgroundColor?: string;
88
};
99

10-
export type ToggledStyles = {
10+
export type ToggledStyle = {
1111
[K in keyof Styles]-?: Required<Styles>[K] extends true ? K : never;
1212
}[keyof Styles];
1313

14-
export type ColorStyles = {
14+
export type ColorStyle = {
1515
[K in keyof Styles]-?: Required<Styles>[K] extends string ? K : never;
1616
}[keyof Styles];
1717

packages/core/src/extensions/FormattingToolbar/FormattingToolbarFactoryTypes.ts

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,12 @@
11
import { EditorElement, ElementFactory } from "../../shared/EditorElement";
2-
import { Block, PartialBlock } from "../Blocks/api/blockTypes";
2+
import { BlockNoteEditor } from "../../BlockNoteEditor";
33

44
export type FormattingToolbarStaticParams = {
5-
toggleBold: () => void;
6-
toggleItalic: () => void;
7-
toggleUnderline: () => void;
8-
toggleStrike: () => void;
9-
setHyperlink: (url: string, text?: string) => void;
10-
11-
setTextColor: (color: string) => void;
12-
setBackgroundColor: (color: string) => void;
13-
setTextAlignment: (
14-
textAlignment: "left" | "center" | "right" | "justify"
15-
) => void;
16-
17-
increaseBlockIndent: () => void;
18-
decreaseBlockIndent: () => void;
19-
20-
updateBlock: (updatedBlock: PartialBlock) => void;
5+
editor: BlockNoteEditor;
216
};
227

238
export type FormattingToolbarDynamicParams = {
24-
boldIsActive: boolean;
25-
italicIsActive: boolean;
26-
underlineIsActive: boolean;
27-
strikeIsActive: boolean;
28-
hyperlinkIsActive: boolean;
29-
activeHyperlinkUrl: string;
30-
activeHyperlinkText: string;
31-
32-
textColor: string;
33-
backgroundColor: string;
34-
textAlignment: "left" | "center" | "right" | "justify";
35-
36-
canIncreaseBlockIndent: boolean;
37-
canDecreaseBlockIndent: boolean;
38-
39-
block: Block;
40-
9+
editor: BlockNoteEditor;
4110
referenceRect: DOMRect;
4211
};
4312

0 commit comments

Comments
 (0)