Media
Embed medias like videos or tweets into your document.
'use client';
import React from 'react';
import { Plate } from '@udecode/plate-common/react';
import { editorPlugins } from '@/components/editor/plugins/editor-plugins';
import { useCreateEditor } from '@/components/editor/use-create-editor';
import { Editor, EditorContainer } from '@/components/plate-ui/editor';
import { DEMO_VALUES } from './values/demo-values';
export default function Demo({ id }: { id: string }) {
const editor = useCreateEditor({
plugins: [...editorPlugins],
value: DEMO_VALUES[id],
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Installation
npm install @udecode/plate-media
Usage
import {
AudioPlugin,
FilePlugin,
ImagePlugin,
MediaEmbedPlugin,
PlaceholderPlugin,
VideoPlugin,
} from '@udecode/plate-media/react';
import { SelectOnBackspacePlugin } from '@udecode/plate-select';
const plugins = [
// ...otherPlugins,
ImagePlugin,
VideoPlugin,
AudioPlugin,
FilePlugin,
MediaEmbedPlugin,
SelectOnBackspacePlugin.configure({
options: {
query: {
allow: [ImagePlugin.key, VideoPlugin.key, AudioPlugin.key, FilePlugin.key, MediaEmbedPlugin.key],
},
},
}),
PlaceholderPlugin.configure({
options: { disableEmptyPlaceholder: true },
render: { afterEditable: MediaUploadToast },
}),
];
const components = {
// ...otherComponents,
[ImagePlugin.key]: ImageElement,
[VideoPlugin.key]: VideoElement,
[AudioPlugin.key]: AudioElement,
[FilePlugin.key]: FileElement,
[MediaEmbedPlugin.key]: MediaEmbedElement,
[PlaceholderPlugin.key]: MediaPlaceholderElement,
};
标题
要启用媒体标题,请使用 Caption Plugin。
上传
有两种方法在您的编辑器中实现文件上传:
- 使用我们的 UploadThing 实现
- 使用您首选的解决方案创建自定义实现
UploadThing
-
添加 MediaPlaceholderElement 组件
-
添加 UploadThing API 路由:
npx shadcx@latest add plate/api-uploadthing
- 从 UploadThing 获取您的秘密密钥
- 将您的 UploadThing 秘密密钥添加到
.env
:
UPLOADTHING_TOKEN=xxx
自定义实现
对于自定义实现,您需要创建一个与我们的接口匹配的上传钩子。这可以与任何上传后端(AWS S3、UploadThing、Cloudinary、Firebase Storage 等)一起使用。
上传钩子应实现此接口:
interface UseUploadFileProps {
onUploadComplete?: (file: UploadedFile) => void;
onUploadError?: (error: unknown) => void;
headers?: Record<string, string>;
onUploadBegin?: (fileName: string) => void;
onUploadProgress?: (progress: { progress: number }) => void;
skipPolling?: boolean;
}
interface UploadedFile {
key: string; // Unique identifier
url: string; // Public URL of the uploaded file
name: string; // Original filename
size: number; // File size in bytes
type: string; // MIME type
}
示例实现使用 S3 预签名 URL:
export function useUploadFile({
onUploadComplete,
onUploadError,
onUploadProgress
}: UseUploadFileProps = {}) {
const [uploadedFile, setUploadedFile] = useState<UploadedFile>();
const [uploadingFile, setUploadingFile] = useState<File>();
const [progress, setProgress] = useState(0);
const [isUploading, setIsUploading] = useState(false);
async function uploadFile(file: File) {
setIsUploading(true);
setUploadingFile(file);
try {
// Get presigned URL and final URL from your backend
const { presignedUrl, fileUrl, fileKey } = await fetch('/api/upload', {
method: 'POST',
body: JSON.stringify({
filename: file.name,
contentType: file.type,
}),
}).then(r => r.json());
// Upload to S3 using presigned URL
await axios.put(presignedUrl, file, {
headers: { 'Content-Type': file.type },
onUploadProgress: (progressEvent) => {
const progress = (progressEvent.loaded / progressEvent.total) * 100;
setProgress(progress);
onUploadProgress?.({ progress });
},
});
const uploadedFile = {
key: fileKey,
url: fileUrl,
name: file.name,
size: file.size,
type: file.type,
};
setUploadedFile(uploadedFile);
onUploadComplete?.(uploadedFile);
return uploadedFile;
} catch (error) {
onUploadError?.(error);
throw error;
} finally {
setProgress(0);
setIsUploading(false);
setUploadingFile(undefined);
}
}
return {
isUploading,
progress,
uploadFile,
uploadedFile,
uploadingFile,
};
}
Examples
Plate UI
参考上面的预览。
Plate Plus
Plugins
PlaceholderPlugin
用于空媒体占位符元素的插件。处理文件上传、拖放和剪贴板粘贴事件。
Options
- 默认:
false
- 默认:
false
- 默认:
5
- 默认:
true
不同文件类型的配置。默认配置:
{
audio: {
maxFileCount: 1,
maxFileSize: '8MB',
mediaType: AudioPlugin.key,
minFileCount: 1,
},
blob: {
maxFileCount: 1,
maxFileSize: '8MB',
mediaType: FilePlugin.key,
minFileCount: 1,
},
image: {
maxFileCount: 3,
maxFileSize: '4MB',
mediaType: ImagePlugin.key,
minFileCount: 1,
},
pdf: {
maxFileCount: 1,
maxFileSize: '4MB',
mediaType: FilePlugin.key,
minFileCount: 1,
},
text: {
maxFileCount: 1,
maxFileSize: '64KB',
mediaType: FilePlugin.key,
minFileCount: 1,
},
video: {
maxFileCount: 1,
maxFileSize: '16MB',
mediaType: VideoPlugin.key,
minFileCount: 1,
},
}
Supported file types: 'image' | 'video' | 'audio' | 'pdf' | 'text' | 'blob'
禁用空占位符,当没有文件上传时。
禁用拖放文件上传功能。
如果未通过 uploadConfig
指定,则一次可以上传的最大文件数量。
允许一次上传多个相同类型的文件。
MediaPluginOptions
媒体插件使用的选项。
Attributes
用于检查文本字符串是否为 URL 的函数。
用于转换 URL 的函数。
ImagePlugin
用于处理空图像元素的插件。选项继承自 MediaPluginOptions。
Options
- 来自
FileReader.readAsDataURL
的数据 URL(字符串) - 来自剪贴板数据的 ArrayBuffer
- 已上传图片的 URL 字符串
- 如果不需要上传,则返回原始数据 URL/ArrayBuffer
继承自 MediaPluginOptions。
一个可选的方法,用于将图片上传到服务器。该方法接收以下参数之一:
应返回以下内容之一:
如果未提供此方法,将使用原始数据 URL/ArrayBuffer 作为图片源。
如果设置为 true,则在数据插入时禁用文件上传。
如果设置为 true,则在数据插入时禁用 URL 嵌入。
VideoPlugin
用于处理空视频元素的插件。
AudioPlugin
用于处理空音频元素的插件。
FilePlugin
用于处理空文件元素的插件。
MediaEmbedPlugin
用于处理空媒体嵌入元素的插件。选项继承自 MediaPluginOptions
。
API 占位符
editor.tf.insert.media()
将媒体文件插入编辑器,并带有上传占位符。
Parameters
要上传的文件。根据配置的文件类型和限制进行验证。
转换过程:
- 根据配置的限制(大小、数量、类型)验证文件
- 为每个文件创建占位符元素
- 按顺序处理多个文件上传
- 维护上传历史以支持撤销/重做操作
- 如果验证失败则触发错误处理
Error codes:
enum UploadErrorCode {
INVALID_FILE_TYPE = 400,
TOO_MANY_FILES = 402,
INVALID_FILE_SIZE = 403,
TOO_LESS_FILES = 405,
TOO_LARGE = 413,
}
editor.tf.insert.audioPlaceholder
插入一个占位符。完成后转换为音频元素。
Parameters
插入节点转换的选项。
editor.tf.insert.filePlaceholder
插入一个占位符。完成后转换为文件元素。
Parameters
插入节点转换的选项。
editor.tf.insert.imagePlaceholder
插入一个占位符。完成后转换为图片元素。
Parameters
插入节点转换的选项。
editor.tf.insert.videoPlaceholder
插入一个占位符。完成后转换为视频元素。
Parameters
插入节点转换的选项。
editor.api.placeholder.addUploadingFile()
跟踪当前正在上传的文件。
Parameters
占位符元素的唯一标识符。
正在上传的文件。
editor.api.placeholder.getUploadingFile()
获取当前正在上传的文件。
Parameters
占位符元素的唯一标识符。
Returns
如果找到则返回正在上传的文件,否则返回 undefined。
editor.api.placeholder.removeUploadingFile()
在上传完成或失败后从上传跟踪状态中移除文件。
Parameters
要移除的占位符元素的唯一标识符。
API Media
parseMediaUrl
根据媒体插件的配置规则解析媒体 URL 并返回相关数据。
Parameters
编辑器实例。
submitFloatingMedia
通过设置 URL 并执行必要的转换来提交浮动媒体元素。
Parameters
编辑器实例。
EmbedUrlData
定义从解析嵌入 URL 返回的数据类型。
Attributes
嵌入内容的 URL。
嵌入内容的提供者。
嵌入内容的唯一 ID。
用于渲染嵌入内容的组件。
API Image
insertImage
在编辑器中插入图片元素。
Parameters
编辑器实例。
图片的 URL 或 ArrayBuffer。
插入图片元素的其他选项。
isImageUrl
检查给定的 URL 是否是有效的图片 URL。
Parameters
要检查的 URL。
withImageUpload
增强编辑器以支持从剪贴板粘贴图片。
Parameters
编辑器实例。
plate 插件。
withImageEmbed
增强编辑器以在粘贴 URL 时自动插入图片。
Parameters
编辑器实例。
plate 插件。
API Media Embed
insertMediaEmbed
在当前选择位置插入媒体嵌入元素。
Parameters
编辑器实例。
插入节点的选项。
parseIframeUrl
解析 iframe 嵌入的 URL。
Parameters
iframe 的 URL 或嵌入代码。
parseTwitterUrl
解析 Twitter URL 并提取推文 ID。
Parameters
Twitter URL。
Returns
如果解析成功,返回包含推文 ID 和提供者的对象。 如果 URL 无效或不匹配任何支持的视频提供者,则返回 undefined。
parseVideoUrl
解析视频 URL 并提取视频 ID 和提供者特定的嵌入 URL。
Parameters
视频 URL。
Returns
如果解析成功,返回包含视频 ID 和提供者的对象。 如果 URL 无效或不匹配任何支持的视频提供者,则返回 undefined。
API Components
useResizable
用于可调整大小元素的行为钩子。
State
可调整大小元素内容的对齐方式。
可调整大小元素的最小宽度。
可调整大小元素的最大宽度。
用于在调整大小时设置节点宽度的函数。
直接设置可调整大小元素宽度的函数。
可调整大小元素的当前宽度。可以是字符串(如百分比或 'auto')或数字(表示像素)。
Returns
指向包装可调整大小元素的最外层 div 的 React 引用。
要传递给包装可调整大小元素的最外层 div 的属性。
要传递给可调整大小元素的属性。
useFloatingMediaEditButton
用于浮动媒体编辑按钮的行为钩子。
Returns
useFloatingMediaUrlInput
用于浮动媒体 URL 输入的行为钩子。
Props
URL 输入字段的默认值。
Returns
useImage
用于图片元素的行为钩子。
Returns
useMediaState
用于媒体元素的状态钩子。
Parameters
Returns
媒体元素的对齐方式。
媒体元素当前是否获得焦点。
媒体元素当前是否被选中。
编辑器是否处于只读模式。
媒体元素的解析嵌入数据。
媒体元素是否为推文。
媒体元素是否为视频。
媒体元素是否为 YouTube 视频。
useMediaToolbarButton
用于媒体工具栏按钮的行为钩子。
Parameters
Returns
类型
TMediaElement
export interface TMediaElement extends TElement {
url: string;
id?: string;
align?: 'center' | 'left' | 'right';
isUpload?: boolean;
name?: string;
placeholderId?: string;
}
TPlaceholderElement
export interface TPlaceholderElement extends TElement {
mediaType: string;
}