自定义内联内容类型
除了 BlockNote 提供的默认内联内容类型外,你还可以使用 React 组件创建自己的自定义内联内容。请看下面的演示,我们在 BlockNote 编辑器中添加了一个自定义的提及标签(mention tag),以及一个用于插入该标签的自定义建议菜单。
import {
BlockNoteSchema,
defaultInlineContentSpecs,
filterSuggestionItems,
} from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import {
DefaultReactSuggestionItem,
SuggestionMenuController,
useCreateBlockNote,
} from "@blocknote/react";
import { Mention } from "./Mention.js";
// Our schema with inline content specs, which contain the configs and
// implementations for inline content that we want our editor to use.
const schema = BlockNoteSchema.create({
inlineContentSpecs: {
// Adds all default inline content.
...defaultInlineContentSpecs,
// Adds the mention tag.
mention: Mention,
},
});
// Function which gets all users for the mentions menu.
const getMentionMenuItems = (
editor: typeof schema.BlockNoteEditor,
): DefaultReactSuggestionItem[] => {
const users = ["Steve", "Bob", "Joe", "Mike"];
return users.map((user) => ({
title: user,
onItemClick: () => {
editor.insertInlineContent([
{
type: "mention",
props: {
user,
},
},
" ", // add a space after the mention
]);
},
}));
};
export function App() {
const editor = useCreateBlockNote({
schema,
initialContent: [
{
type: "paragraph",
content: "Welcome to this demo!",
},
{
type: "paragraph",
content: [
{
type: "mention",
props: {
user: "Steve",
},
},
{
type: "text",
text: " <- This is an example mention",
styles: {},
},
],
},
{
type: "paragraph",
content: "Press the '@' key to open the mentions menu and add another",
},
{
type: "paragraph",
},
],
});
return (
<BlockNoteView editor={editor}>
{/* Adds a mentions menu which opens with the "@" key */}
<SuggestionMenuController
triggerCharacter={"@"}
getItems={async (query) =>
// Gets the mentions menu items
filterSuggestionItems(getMentionMenuItems(editor), query)
}
/>
</BlockNoteView>
);
}
export default App;
创建自定义内联内容类型
使用 createReactInlineContentSpec
函数来创建自定义内联内容类型。该函数接受两个参数:
function createReactInlineContentSpec(
blockConfig: CustomInlineContentConfig,
blockImplementation: ReactInlineContentImplementation,
);
让我们看看演示中的自定义提及标签,并逐个字段解释其作用:
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
。
在提及示例中,我们希望每个提及是一个单独的、不可编辑的元素,所以设置为 "none"
。
propSchema
PropSchema
指定内联内容支持的 props。内联内容的 props(属性)是在文档中随内联内容存储的数据,可以用来定制其外观或行为。
type PropSchema<
PrimitiveType extends "boolean" | "number" | "string"
> = Record<
string,
{
default: PrimitiveType;
values?: PrimitiveType[];
}
>
[key: string]
是 prop 的名称,值是包含两个字段的对象:
-
default
:指定该 prop 的默认值 -
values
(可选):指定该 prop 可以取的值的数组,例如限制该值为预定义字符串列表。如果未定义values
,BlockNote 认为该 prop 可以是任何PrimitiveType
的值
在提及演示中,我们添加了一个 user
prop,用于指定被提及的用户。
内联内容实现 (ReactCustomInlineContentImplementation
)
内联内容实现定义了内联内容如何渲染为 HTML。
type ReactCustomInlineContentImplementation = {
render: React.FC<{
inlineContent: InlineContent;
contentRef?: (node: HTMLElement | null) => void;
}>;
};
render
这是你的 React 组件,用于定义自定义内联内容的渲染方式,接受两个 React props:
inlineContent:
需要渲染的内联内容。其类型和 props 会匹配内联内容配置中定义的类型和 PropSchema
。
contentRef:
React ref
,用于标记内联内容中可编辑的元素,仅当你的内联内容配置中包含 content: "styled"
时提供。
注意,由于内联内容本质上是内联的,你的组件也应返回一个 HTML 内联元素。
向编辑器添加自定义内联内容
最后,使用你自定义内联内容的定义创建一个 BlockNoteSchema:
const schema = BlockNoteSchema.create({
inlineContentSpecs: {
// 如果需要,可以启用默认内联内容
...defaultInlineContentSpecs,
// 添加你自己的自定义内联内容:
mention: Mention,
},
});
然后如自定义 Schema 页面所述,用该自定义 schema 实例化编辑器即可。