🚀 BlockNote AI is here! Access the early preview.
BlockNote Docs/Features/自定义模式/自定义内联内容

自定义内联内容类型

除了 BlockNote 提供的默认内联内容类型外,您还可以使用 React 组件创建自己的自定义内联内容。请看下面的示例演示,我们在 BlockNote 编辑器中添加了一个自定义提及标签,以及一个自定义的 建议菜单 用于插入它。

创建自定义内联内容类型

使用 createReactInlineContentSpec 函数来创建自定义内联内容类型。该函数接受两个参数:

function createReactInlineContentSpec(
  blockConfig: CustomInlineContentConfig,
  blockImplementation: ReactInlineContentImplementation,
): InlineContentSpec;

它返回您的自定义内联内容的实例,或者一个 InlineContentSpec。此 InlineContentSpec 会传递到您的 BlockNote schema 中,以将内联内容添加到编辑器。

让我们看看演示中的自定义提及标签,并逐个字段解释其作用:

const Mention = createReactInlineContentSpec(
  {
    type: "mention",
    propSchema: {
      user: {
        default: "Unknown",
      },
    },
    content: "none",
  } as const,
  {
    render: (props) => (
      ...
    ),
  }
);

内联内容配置 (CustomInlineContentConfig)

内联内容配置描述你的自定义内联内容的结构。用它来指定自定义内联内容应该支持的类型、属性(props)和内容:

type CustomInlineContentConfig = {
  type: string;
  content: "styled" | "none";
  readonly propSchema: PropSchema;
};

type: 定义自定义内联内容的标识符。

content: 如果您的自定义内联内容应包含 StyledText,则设置为 styled,如果不包含,则设置为 none

在提及标签示例中,我们希望每个提及都是一个不可编辑的单一元素,因此将 content 设置为 "none"

propSchema: PropSchema 指定内联内容支持的属性。内联内容的 props 是随文档中内联内容一起存储的数据,可用于自定义其外观或行为。

type PropSchema<PrimitiveType extends "boolean" | "number" | "string"> = Record<
  string,
  | {
      default: PrimitiveType;
      values?: PrimitiveType[];
    }
  | {
      default: undefined;
      type: PrimitiveType;
      values?: PrimitiveType[];
    }
>;

[key: string] 是属性的名称。如果希望该属性有默认值,则应定义为具有以下属性的对象:

  • default: 指定属性的默认值,由此推断 PrimitiveType

  • values?: 指定该属性可取的值的数组,例如,用于限制值为预定义字符串列表。如果未定义 values,BlockNote 默认属性可以是任何 PrimitiveType 类型的值。

如果不希望该属性有默认值,可以定义为具有以下属性的对象:

  • default: 设为 undefined,表示无默认值。

  • type: 指定该属性可以设置的 PrimitiveType,因为默认值为 undefined,无法推断类型。

  • values?: 指定该属性可取的值的数组,例如限制为预定义字符串列表。如果未定义 values,BlockNote 默认属性可以是任何 PrimitiveType 类型的值。

在提及标签示例中,我们为被提及的用户添加了一个 user 属性。

draggable?: 指定该内联内容是否可以被拖拽。

内联内容实现 (ReactCustomInlineContentImplementation)

内联内容实现定义了内联内容如何渲染为 HTML。

type ReactCustomInlineContentImplementation = {
  meta?: {
    draggable?: boolean;
  };
  render: React.FC<{
    inlineContent: InlineContent;
    editor: BlockNoteEditor;
    contentRef?: (node: HTMLElement | null) => void;
  }>;
  toExternalHTML?: React.FC<{
    inlineContent: InlineContent;
    editor: BlockNoteEditor;
    contentRef?: (node: HTMLElement | null) => void;
  }>;
  parse?: (element: HTMLElement) => PartialInlineContent["props"] | undefined;
};

render: 这是您的 React 组件,定义了如何渲染自定义内联内容,并接收三个 React props:

  • inlineContent: 应渲染的内联内容。其类型和属性将匹配内联内容配置中定义的类型和 PropSchema

  • contentRef: 一个 React ref,可用于标记内联内容中可编辑的元素,仅当内联内容配置包含 content: "styled" 时可用。

  • draggable: 指定内联内容是否可以在编辑器内拖动。设置为 true 时,内联内容将可拖动。若未指定,默认为 false。若为 true,应在用作拖动句柄的 DOM 元素上添加 data-drag-handle 属性。

toExternalHTML?: 该组件用于将内联内容导出为外部 HTML(例如复制到剪贴板时)。如果未定义,BlockNote 将使用 render 进行 HTML 转换。接收与 render 相同的 props。

注意,传递给 toExternalHTML 的组件会在单独的 React 根中渲染和序列化,这意味着您不能使用依赖 React Context 的 hooks。

parse?: parse 函数定义如何将 HTML 内容解析为您的内联内容,例如从剪贴板粘贴内容时。如果元素应被解析为您的自定义内联内容,则返回该内联内容应具有的 props,否则返回 undefined。接收一个参数:

  • element: 正在解析的 HTML 元素。

meta?.draggable?: 指定内联内容是否可拖动。

注意,由于内联内容本质上是内联的,您的组件应返回一个 HTML 内联元素。

向编辑器添加自定义内联内容

最后,使用您自定义内联内容的定义创建一个 BlockNoteSchema:

const schema = BlockNoteSchema.create({
  inlineContentSpecs: {
    // 如需要,可启用默认内联内容
    ...defaultInlineContentSpecs,

    // 添加您自己的自定义内联内容:
    mention: Mention,
  },
});

然后您可以使用此自定义 schema 实例化您的编辑器,具体方法请参见 自定义 Schema 页面。