AgentSkillsCN

rte-plugins

为@mentions与文件上传功能使用富文本编辑器插件。当您需要实现提及功能、上传文件,或开发自定义插件时,这一功能同样不可或缺。

SKILL.md
--- frontmatter
name: rte-plugins
description: Use Rich Text Editor plugins for @mentions and file uploads. Use when implementing mentions, file attachments, or creating custom plugins.

Plugins

Mention Plugin

tsx
import {
  RichTextEditor,
  createMentionPlugin,
  type MentionItem,
} from '@/components/ui/editor'

const users: MentionItem[] = [
  { id: '1', label: 'John Doe', avatar: 'https://...' },
  { id: '2', label: 'Jane Smith' },
]

const mentionPlugin = createMentionPlugin({
  onSearch: async (query) => {
    return users.filter(u =>
      u.label.toLowerCase().includes(query.toLowerCase())
    )
  },
})

<RichTextEditor plugins={[mentionPlugin]} />

MentionPluginOptions

OptionTypeDefaultDescription
onSearch(query) => MentionItem[]requiredSearch handler
triggerstring'@'Trigger character
allowSpacesbooleanfalseAllow spaces in query
minQueryLengthnumber0Min chars to search
maxSuggestionsnumber10Max dropdown items
debounceMsnumber150Search debounce
noResultsTextstring'No results found'Empty state text
loadingTextstring'Searching...'Loading text
renderItem(item, selected) => ReactNode-Custom item render
renderMention(item) => ReactNode-Custom mention render
onMentionSelect(item) => void-Selection callback
onMentionRemove(item) => void-Removal callback
onMentionClick(item, event) => void-Click callback

File Upload Plugin

tsx
import {
  RichTextEditor,
  createFileUploadPlugin,
} from '@/components/ui/editor'

const filePlugin = createFileUploadPlugin({
  onUpload: async (file) => {
    const formData = new FormData()
    formData.append('file', file)
    const res = await fetch('/api/upload', { method: 'POST', body: formData })
    const { url } = await res.json()
    return url
  },
})

<RichTextEditor plugins={[filePlugin]} />

FileUploadPluginOptions

OptionTypeDefaultDescription
onUpload(file) => Promise<string>requiredUpload handler, returns URL
acceptstring[]-Allowed types ['image/*', '.pdf']
maxSizenumber10MBMax file size in bytes
defaultDisplayMode'block' | 'inline''inline'Default display
displayModeByTypeRecord<string, 'block'|'inline'>-Per-type display
onUploadStart(file) => void-Upload started
onUploadComplete(file, url) => void-Upload succeeded
onUploadError(file, error) => void-Upload failed
onFileDelete(src, name, mimeType) => void-File deleted
onFetchFile(src, mimeType) => Promise<string|Blob>-Custom file fetcher
previewOptionsPreviewOptions-Preview customization

Display Mode by Type

tsx
createFileUploadPlugin({
  onUpload: uploadFn,
  displayModeByType: {
    'image/*': 'block',
    'application/pdf': 'block',
    'text/*': 'inline',
    '*': 'inline',
  },
})

Combining Plugins

tsx
const plugins = [
  createMentionPlugin({ onSearch: searchUsers }),
  createFileUploadPlugin({ onUpload: uploadFile }),
]

<RichTextEditor plugins={plugins} />

Custom Plugin

tsx
import type { EditorPlugin, SlashCommand, ToolbarAction } from '@/components/ui/editor'

const myPlugin: EditorPlugin = {
  name: 'my-plugin',

  slashCommands: [{
    name: 'Custom',
    description: 'My command',
    icon: Sparkles,
    group: 'custom',
    action: (editor) => { /* ... */ },
  }],

  toolbarActions: [{
    id: 'custom-action',
    icon: Sparkles,
    label: 'Custom',
    isActive: (editor) => false,
    action: (editor) => { /* ... */ },
  }],

  extensions: [], // Tiptap extensions

  onInit: (editor) => { /* setup */ },
  onDestroy: () => { /* cleanup */ },
}

MentionItem

tsx
interface MentionItem {
  id: string
  label: string
  avatar?: string
  metadata?: Record<string, unknown>
}