Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 30 additions & 7 deletions examples/02-ui-components/02-formatting-toolbar-buttons/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,57 +70,80 @@ export default function App() {
return (
<BlockNoteView editor={editor} formattingToolbar={false}>
<FormattingToolbarController
formattingToolbar={() => (
<FormattingToolbar>
<BlockTypeDropdown key={"blockTypeDropdown"} />
formattingToolbar={(props) => (
<FormattingToolbar {...props}>
<BlockTypeDropdown
selectedBlocks={props.selectedBlocks}
key={"blockTypeDropdown"}
/>

{/* Extra button to toggle blue text & background */}
<BlueButton key={"customButton"} />

<ImageCaptionButton key={"imageCaptionButton"} />
<ReplaceImageButton key={"replaceImageButton"} />
<ImageCaptionButton
selectedBlocks={props.selectedBlocks}
key={"imageCaptionButton"}
/>
<ReplaceImageButton
selectedBlocks={props.selectedBlocks}
key={"replaceImageButton"}
/>

<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"bold"}
key={"boldStyleButton"}
/>
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"italic"}
key={"italicStyleButton"}
/>
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"underline"}
key={"underlineStyleButton"}
/>
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"strike"}
key={"strikeStyleButton"}
/>
{/* Extra button to toggle code styles */}
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
key={"codeStyleButton"}
basicTextStyle={"code"}
/>

<TextAlignButton
selectedBlocks={props.selectedBlocks}
textAlignment={"left"}
key={"textAlignLeftButton"}
/>
<TextAlignButton
selectedBlocks={props.selectedBlocks}
textAlignment={"center"}
key={"textAlignCenterButton"}
/>
<TextAlignButton
selectedBlocks={props.selectedBlocks}
textAlignment={"right"}
key={"textAlignRightButton"}
/>

<ColorStyleButton key={"colorStyleButton"} />
<ColorStyleButton
selectedBlocks={props.selectedBlocks}
key={"colorStyleButton"}
/>

<NestBlockButton key={"nestBlockButton"} />
<UnnestBlockButton key={"unnestBlockButton"} />

<CreateLinkButton key={"createLinkButton"} />
<CreateLinkButton
selectedBlocks={props.selectedBlocks}
key={"createLinkButton"}
/>
</FormattingToolbar>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ export default function App() {
return (
<BlockNoteView editor={editor} formattingToolbar={false}>
<FormattingToolbarController
formattingToolbar={() => (
formattingToolbar={(props) => (
<FormattingToolbar
{...props}
blockTypeDropdownItems={[
...blockTypeDropdownItems,
{
Expand Down
36 changes: 29 additions & 7 deletions examples/05-custom-schema/03-font-style/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,51 +97,73 @@ export default function App() {
<BlockNoteView editor={editor} formattingToolbar={false}>
{/* Replaces the default Formatting Toolbar. */}
<FormattingToolbarController
formattingToolbar={() => (
<FormattingToolbar>
<BlockTypeDropdown key={"blockTypeDropdown"} />
formattingToolbar={(props) => (
<FormattingToolbar {...props}>
<BlockTypeDropdown
selectedBlocks={props.selectedBlocks}
key={"blockTypeDropdown"}
/>

<ImageCaptionButton key={"imageCaptionButton"} />
<ReplaceImageButton key={"replaceImageButton"} />
<ImageCaptionButton
selectedBlocks={props.selectedBlocks}
key={"imageCaptionButton"}
/>
<ReplaceImageButton
selectedBlocks={props.selectedBlocks}
key={"replaceImageButton"}
/>

<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"bold"}
key={"boldStyleButton"}
/>
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"italic"}
key={"italicStyleButton"}
/>
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"underline"}
key={"underlineStyleButton"}
/>
<BasicTextStyleButton
selectedBlocks={props.selectedBlocks}
basicTextStyle={"strike"}
key={"strikeStyleButton"}
/>
{/* Adds SetFontStyleButton */}
<SetFontStyleButton />

<TextAlignButton
selectedBlocks={props.selectedBlocks}
textAlignment={"left"}
key={"textAlignLeftButton"}
/>
<TextAlignButton
selectedBlocks={props.selectedBlocks}
textAlignment={"center"}
key={"textAlignCenterButton"}
/>
<TextAlignButton
selectedBlocks={props.selectedBlocks}
textAlignment={"right"}
key={"textAlignRightButton"}
/>

<ColorStyleButton key={"colorStyleButton"} />
<ColorStyleButton
selectedBlocks={props.selectedBlocks}
key={"colorStyleButton"}
/>

<NestBlockButton key={"nestBlockButton"} />
<UnnestBlockButton key={"unnestBlockButton"} />

<CreateLinkButton key={"createLinkButton"} />
<CreateLinkButton
selectedBlocks={props.selectedBlocks}
key={"createLinkButton"}
/>
</FormattingToolbar>
)}
/>
Expand Down
8 changes: 4 additions & 4 deletions examples/05-custom-schema/react-custom-blocks/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@ export const bracketsParagraphBlock = createReactBlockSpec(
{
render: (props) => (
<div className={"brackets-paragraph"}>
<div contentEditable={"false"}>{"["}</div>
<span contentEditable={"false"}>{"{"}</span>
<div>{"["}</div>
<span>{"{"}</span>
<div className={"inline-content"} ref={props.contentRef} />
<span contentEditable={"false"}>{"}"}</span>
<div contentEditable={"false"}>{"]"}</div>
<span>{"}"}</span>
<div>{"]"}</div>
</div>
),
}
Expand Down
2 changes: 1 addition & 1 deletion examples/05-custom-schema/react-custom-styles/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const CustomFormattingToolbar = (props: FormattingToolbarProps) => {
const activeStyles = useActiveStyles(editor);

return (
<FormattingToolbar>
<FormattingToolbar {...props}>
<ToolbarButton
mainTooltip={"small"}
onClick={() => {
Expand Down
2 changes: 1 addition & 1 deletion examples/vanilla-js/react-vanilla-custom-styles/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const CustomFormattingToolbar = (props: FormattingToolbarProps) => {
const activeStyles = useActiveStyles(editor);

return (
<FormattingToolbar>
<FormattingToolbar {...props}>
<ToolbarButton
mainTooltip={"small"}
onClick={() => {
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/editor/BlockNoteEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ export class BlockNoteEditor<
public readonly inlineContentImplementations: InlineContentSpecs;
public readonly styleImplementations: StyleSpecs;

public readonly formattingToolbar: FormattingToolbarProsemirrorPlugin;
public readonly formattingToolbar: FormattingToolbarProsemirrorPlugin<
BSchema,
ISchema,
SSchema
>;
public readonly hyperlinkToolbar: HyperlinkToolbarProsemirrorPlugin<
BSchema,
ISchema,
Expand Down Expand Up @@ -361,7 +365,7 @@ export class BlockNoteEditor<
* @deprecated, use `editor.document` instead
*/
public get topLevelBlocks(): Block<BSchema, ISchema, SSchema>[] {
return this.topLevelBlocks;
return this.document;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
import { UiElementPosition } from "../../extensions-shared/UiElementPosition";
import { BlockSchema, InlineContentSchema, StyleSchema } from "../../schema";
import { EventEmitter } from "../../util/EventEmitter";

export type FormattingToolbarState = UiElementPosition;

export class FormattingToolbarView {
public state?: FormattingToolbarState;
import { Block } from "../../blocks/defaultBlocks";

export type FormattingToolbarState<
BSchema extends BlockSchema,
I extends InlineContentSchema,
S extends StyleSchema
> = UiElementPosition & {
selectedBlocks: Block<BSchema, I, S>[];
};

export class FormattingToolbarView<
BSchema extends BlockSchema,
I extends InlineContentSchema,
S extends StyleSchema
> {
public state?: FormattingToolbarState<BSchema, I, S>;
public emitUpdate: () => void;

public preventHide = false;
Expand All @@ -25,13 +36,9 @@ export class FormattingToolbarView {
}) => boolean = ({ state }) => !state.selection.empty;

constructor(
private readonly editor: BlockNoteEditor<
BlockSchema,
InlineContentSchema,
StyleSchema
>,
private readonly editor: BlockNoteEditor<BSchema, I, S>,
private readonly pmView: EditorView,
emitUpdate: (state: FormattingToolbarState) => void
emitUpdate: (state: FormattingToolbarState<BSchema, I, S>) => void
) {
this.emitUpdate = () => {
if (!this.state) {
Expand Down Expand Up @@ -145,9 +152,14 @@ export class FormattingToolbarView {
!this.preventShow &&
(shouldShow || this.preventHide)
) {
const blockWithTextCursor = this.editor.getTextCursorPosition().block;
const selection = this.editor.getSelection();

this.state = {
show: true,
referencePos: this.getSelectionBoundingBox(),
selectedBlocks:
selection !== undefined ? selection.blocks : [blockWithTextCursor],
};

this.emitUpdate();
Expand Down Expand Up @@ -205,11 +217,15 @@ export const formattingToolbarPluginKey = new PluginKey(
"FormattingToolbarPlugin"
);

export class FormattingToolbarProsemirrorPlugin extends EventEmitter<any> {
private view: FormattingToolbarView | undefined;
export class FormattingToolbarProsemirrorPlugin<
BSchema extends BlockSchema,
I extends InlineContentSchema,
S extends StyleSchema
> extends EventEmitter<any> {
private view: FormattingToolbarView<BSchema, I, S> | undefined;
public readonly plugin: Plugin;

constructor(editor: BlockNoteEditor<any, any, any>) {
constructor(editor: BlockNoteEditor<BSchema, I, S>) {
super();
this.plugin = new Plugin({
key: formattingToolbarPluginKey,
Expand All @@ -222,7 +238,9 @@ export class FormattingToolbarProsemirrorPlugin extends EventEmitter<any> {
});
}

public onUpdate(callback: (state: FormattingToolbarState) => void) {
public onUpdate(
callback: (state: FormattingToolbarState<BSchema, I, S>) => void
) {
return this.on("update", callback);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {
BlockSchema,
DefaultBlockSchema,
DefaultInlineContentSchema,
DefaultProps,
DefaultStyleSchema,
InlineContentSchema,
StyleSchema,
} from "@blocknote/core";
Expand Down Expand Up @@ -29,14 +32,14 @@ const textAlignmentToPlacement = (
}
};

export const FormattingToolbarController = (props: {
formattingToolbar?: FC<FormattingToolbarProps>;
export const FormattingToolbarController = <
BSchema extends BlockSchema = DefaultBlockSchema,
I extends InlineContentSchema = DefaultInlineContentSchema,
S extends StyleSchema = DefaultStyleSchema
>(props: {
formattingToolbar?: FC<FormattingToolbarProps<BSchema, I, S>>;
}) => {
const editor = useBlockNoteEditor<
BlockSchema,
InlineContentSchema,
StyleSchema
>();
const editor = useBlockNoteEditor<BSchema, I, S>();

const [placement, setPlacement] = useState<"top-start" | "top" | "top-end">(
() => {
Expand Down Expand Up @@ -83,11 +86,13 @@ export const FormattingToolbarController = (props: {
return null;
}

const { show, referencePos, ...data } = state;

const Component = props.formattingToolbar || FormattingToolbar;

return (
<div ref={ref} style={style}>
<Component />
<Component {...data} />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import { BlockTypeDropdownItem } from "./mantine/DefaultDropdowns/BlockTypeDropdown";
import {
BlockSchema,
DefaultBlockSchema,
DefaultInlineContentSchema,
DefaultStyleSchema,
FormattingToolbarState,
InlineContentSchema,
StyleSchema,
UiElementPosition,
} from "@blocknote/core";

export type FormattingToolbarProps = {
export type FormattingToolbarProps<
BSchema extends BlockSchema = DefaultBlockSchema,
I extends InlineContentSchema = DefaultInlineContentSchema,
S extends StyleSchema = DefaultStyleSchema
> = Omit<FormattingToolbarState<BSchema, I, S>, keyof UiElementPosition> & {
blockTypeDropdownItems?: BlockTypeDropdownItem[];
};
Loading