Skip to content
Open
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
9 changes: 9 additions & 0 deletions packages/react/src/hooks/useActiveStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import { BlockNoteEditor, Styles, StyleSchema } from "@blocknote/core";
import { useBlockNoteContext } from "../editor/BlockNoteContext.js";
import { useEditorState } from "./useEditorState.js";

/**
* Returns the currently active text styles (e.g., bold, italic) at the editor's
* current cursor position or selection. Re-renders automatically when the active
* styles change.
*
* @param editor - The BlockNote editor instance. If omitted, uses the editor
* from the nearest `BlockNoteContext`.
* @returns The set of active styles at the current cursor position or selection.
*/
export function useActiveStyles<T extends StyleSchema>(
editor?: BlockNoteEditor<any, any, T>,
): Styles<T> {
Expand Down
9 changes: 9 additions & 0 deletions packages/react/src/hooks/useEditorChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import type { BlockNoteEditor } from "@blocknote/core";
import { useEffect } from "react";
import { useBlockNoteContext } from "../editor/BlockNoteContext.js";

/**
* Subscribes to editor content changes. The callback is invoked whenever the
* editor's document is modified, and the subscription is automatically cleaned
* up when the component unmounts.
*
* @param callback - Function called when the editor content changes.
* @param editor - The BlockNote editor instance. If omitted, uses the editor
* from the nearest `BlockNoteContext`.
*/
export function useEditorChange(
callback: Parameters<BlockNoteEditor<any, any, any>["onChange"]>[0],
editor?: BlockNoteEditor<any, any, any>,
Expand Down
12 changes: 12 additions & 0 deletions packages/react/src/hooks/useEditorSelectionBoundingBox.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import type { BlockNoteEditor } from "@blocknote/core";
import { useEditorState } from "./useEditorState.js";

/**
* Returns the bounding box (`DOMRect`) of the current editor selection.
* Re-renders automatically when the selection changes. Useful for positioning
* floating UI elements (e.g., toolbars, tooltips) relative to the selection.
*
* @param enabled - Whether to compute the bounding box. When `false`, returns
* `undefined` without measuring.
* @param editor - The BlockNote editor instance. If omitted, uses the editor
* from the nearest `BlockNoteContext`.
* @returns The `DOMRect` of the current selection, or `undefined` if disabled
* or no selection exists.
*/
export function useEditorSelectionBoundingBox(
enabled?: boolean,
editor?: BlockNoteEditor<any, any, any>,
Expand Down
11 changes: 11 additions & 0 deletions packages/react/src/hooks/useEditorSelectionChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ import type { BlockNoteEditor } from "@blocknote/core";
import { useEffect } from "react";
import { useBlockNoteContext } from "../editor/BlockNoteContext.js";

/**
* Subscribes to editor selection changes. The callback is invoked whenever the
* user's cursor position or text selection changes, and the subscription is
* automatically cleaned up when the component unmounts.
*
* @param callback - Function called when the selection changes.
* @param editor - The BlockNote editor instance. If omitted, uses the editor
* from the nearest `BlockNoteContext`.
* @param includeSelectionChangedByRemote - Whether to also fire the callback
* when the selection is changed by a remote collaborator. Defaults to `false`.
*/
export function useEditorSelectionChange(
callback: () => void,
editor?: BlockNoteEditor<any, any, any>,
Expand Down
12 changes: 12 additions & 0 deletions packages/react/src/hooks/useFocusWithin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ function containsRelatedTarget(event: FocusEvent) {
return false;
}

/**
* Tracks whether focus is within a referenced DOM element. Returns a ref to
* attach to the target element and a `focused` boolean that is `true` whenever
* the element or any of its descendants has focus.
*
* Adapted from Mantine's `useFocusWithin` hook.
*
* @param options - Optional `onFocus` and `onBlur` callbacks fired when focus
* enters or leaves the element.
* @returns An object with a `ref` to attach to the target element and a
* `focused` boolean indicating current focus-within state.
*/
export function useFocusWithin<T extends HTMLElement = any>({
onBlur,
onFocus,
Expand Down
8 changes: 8 additions & 0 deletions packages/react/src/hooks/useOnUploadEnd.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { useEffect } from "react";
import { useBlockNoteEditor } from "./useBlockNoteEditor.js";

/**
* Subscribes to file upload completion events. The callback is invoked whenever
* a file upload finishes within the editor, and the subscription is
* automatically cleaned up when the component unmounts.
*
* @param callback - Function called when an upload completes. Receives the
* `blockId` of the block whose upload finished, if available.
*/
export function useOnUploadEnd(callback: (blockId?: string) => void) {
const editor = useBlockNoteEditor();

Expand Down
8 changes: 8 additions & 0 deletions packages/react/src/hooks/useOnUploadStart.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { useEffect } from "react";
import { useBlockNoteEditor } from "./useBlockNoteEditor.js";

/**
* Subscribes to file upload start events. The callback is invoked whenever a
* file upload begins within the editor, and the subscription is automatically
* cleaned up when the component unmounts.
*
* @param callback - Function called when an upload starts. Receives the
* `blockId` of the block where the upload was initiated, if available.
*/
export function useOnUploadStart(callback: (blockId?: string) => void) {
const editor = useBlockNoteEditor();

Expand Down
9 changes: 9 additions & 0 deletions packages/react/src/hooks/usePrefersColorScheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
// issues when used in a NextJS project.
import { useEffect, useMemo, useState } from "react";

/**
* Returns the user's preferred color scheme (`"dark"`, `"light"`, or
* `"no-preference"`) based on the `prefers-color-scheme` media query.
* Automatically updates when the system preference changes.
*
* Adapted from the `use-prefers-color-scheme` package.
*
* @returns `"dark"`, `"light"`, or `"no-preference"`.
*/
export const usePrefersColorScheme = () => {
const darkQuery = useMemo(
() => window.matchMedia?.("(prefers-color-scheme: dark)"),
Expand Down
10 changes: 10 additions & 0 deletions packages/react/src/hooks/useSelectedBlocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import {
} from "@blocknote/core";
import { useEditorState } from "./useEditorState.js";

/**
* Returns the blocks that are currently selected in the editor. If no
* multi-block selection exists, returns an array containing the single block
* at the text cursor position. Re-renders automatically when the selection
* changes.
*
* @param editor - The BlockNote editor instance. If omitted, uses the editor
* from the nearest `BlockNoteContext`.
* @returns An array of the currently selected blocks.
*/
export function useSelectedBlocks<
BSchema extends BlockSchema,
ISchema extends InlineContentSchema,
Expand Down
7 changes: 7 additions & 0 deletions packages/react/src/hooks/useUploadLoading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import { useState } from "react";
import { useOnUploadEnd } from "./useOnUploadEnd.js";
import { useOnUploadStart } from "./useOnUploadStart.js";

/**
* Tracks whether a file upload is in progress for a specific block. Returns
* `true` while the upload is active and `false` otherwise.
*
* @param blockId - The ID of the block to monitor for upload activity.
* @returns `true` if a file upload is currently in progress for the given block.
*/
export function useUploadLoading(blockId?: string) {
const [showLoader, setShowLoader] = useState(false);

Expand Down
15 changes: 13 additions & 2 deletions packages/react/src/schema/ReactInlineContentSpec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,19 @@ export function InlineContentWrapper<
);
}

// A function to create custom block for API consumers
// we want to hide the tiptap node from API consumers and provide a simpler API surface instead
/**
* Creates a custom inline content specification for use with React. This is the
* React counterpart to the vanilla `createInlineContentSpec` and lets you define
* custom inline content types (e.g., mentions, tags) using React components for
* rendering.
*
* @param inlineContentConfig - The inline content type configuration, including
* its `type` name, `propSchema`, and `content` mode (`"styled"` or `"none"`).
* @param inlineContentImplementation - The React implementation, including a
* `render` component and optionally a `toExternalHTML` component and `parse`
* rules.
* @returns An `InlineContentSpec` that can be passed to the editor's schema.
*/
export function createReactInlineContentSpec<
const T extends CustomInlineContentConfig,
// I extends InlineContentSchema,
Expand Down
13 changes: 11 additions & 2 deletions packages/react/src/schema/ReactStyleSpec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,17 @@ export type ReactCustomStyleImplementation<T extends StyleConfig> = {
runsBefore?: string[];
};

// A function to create custom block for API consumers
// we want to hide the tiptap node from API consumers and provide a simpler API surface instead
/**
* Creates a custom style specification for use with React. This is the React
* counterpart to the vanilla `createStyleSpec` and lets you define custom text
* styles (e.g., font color, highlight) using React components for rendering.
*
* @param styleConfig - The style configuration, including its `type` name and
* `propSchema` (`"boolean"` or `"string"`).
* @param styleImplementation - The React implementation, including a `render`
* component that receives the style value, a `contentRef`, and the editor.
* @returns A style spec that can be passed to the editor's schema.
*/
export function createReactStyleSpec<T extends StyleConfig>(
styleConfig: T,
styleImplementation: ReactCustomStyleImplementation<T>,
Expand Down
Loading