編輯器

Editor Suggestion Menu

參考
輸入 / 觸發浮動選單;挑選指令執行對應動作。

安裝

Terminal
pnpm dlx shadcn-vue add @admin/editor-suggestion-menu
import type { EditorSuggestionMenuItem } from '@/registry/admin/ui/editor-suggestion-menu'import { AdminEditorSuggestionMenu } from '@/registry/admin/ui/editor-suggestion-menu'

admin-editor-suggestion-menu 只依賴 @admin/editor-core(menu popup engine 與共用型別);handlers 由呼叫端顯式傳入,可搭 <AdminRichEditor> 或 base <AdminEditor> 使用。

用法

在 <admin-rich-editor v-slot="{ editor, handlers }"> slot 內加 <admin-editor-suggestion-menu :editor :handlers :items="...">。輸入 / 觸發 popup。

<script setup lang="ts">import type { JSONContent } from '@tiptap/core'import type { EditorSuggestionMenuItem } from '@/components/admin/editor-suggestion-menu'import { ref } from 'vue'import { cn } from '@/lib/utils'import { baseProseClass } from '@/components/admin/editor'import { AdminEditorSuggestionMenu } from '@/components/admin/editor-suggestion-menu'import { AdminEditorToolbar, defaultEditorItems } from '@/components/admin/editor-toolbar'import { AdminRichEditor, starterKitProseClass } from '@/components/admin/rich-editor'​const value = ref<JSONContent | string>('<p>輸入 / 觸發 slash command menu</p>')​const slashItems: EditorSuggestionMenuItem[] = [  { kind: 'heading', level: 1, label: '標題 1', description: '大標題' },  { kind: 'heading', level: 2, label: '標題 2', description: '中標題' },  { kind: 'heading', level: 3, label: '標題 3', description: '小標題' },  { kind: 'paragraph', label: '內文', description: '一般段落' },  { kind: 'bulletList', label: '項目清單' },  { kind: 'orderedList', label: '數字清單' },  { kind: 'blockquote', label: '引言' }]</script>​<template>  <admin-rich-editor    v-slot="{ editor, handlers }"    v-model="value"    :ui="{ base: cn(baseProseClass, starterKitProseClass) }"  >    <admin-editor-toolbar :editor :handlers="handlers" :items="defaultEditorItems" />    <admin-editor-suggestion-menu :editor :handlers="handlers" :items="slashItems" />  </admin-rich-editor></template>

EditorSuggestionMenuItem 介面

type EditorSuggestionMenuItem = EditorItem & {  label: string  description?: string  icon?: Component | string}

EditorItem 是 admin-editor-core 定義的 discriminated union(admin-rich-editor 也有 re-export),涵蓋 mark / heading / link、12 個無參數 kind 與自訂 handler kind。它直接重用 toolbar items 的結構,寫過 toolbar 就會寫:

const slashItems: EditorSuggestionMenuItem[] = [  { kind: 'heading', level: 1, label: '標題 1' },  { kind: 'bulletList', label: '項目清單' },  { kind: 'blockquote', label: '引言' }]

選定 item 後 SFC 內部會:

  1. 用 editor.chain().focus().deleteRange(range) 刪掉 /xxx 觸發範圍
  2. 透過 props.handlers 取出 handler[item.kind](handlers 由呼叫端顯式傳入,可取自 <AdminRichEditor v-slot="{ editor, handlers }"> 或 base editor 情境的 createDefaultHandlers())
  3. 呼叫 handler.execute(editor, item).run()

由於與 toolbar items 共用 kind dispatch,對應 extension 未啟用時,選取後不會有動作(不會報錯)。

鍵盤導航

由 useEditorMenu composable 提供,不需額外設定:

按鍵行為
ArrowUp / ArrowDown上下移動選取
Enter / Tab確認選取
Escape關閉 popup

選取 label / separator type 的 item 會自動跳過。

與 toolbar items 共用結構

suggestion menu 的 :items 接受扁平或分組陣列。defaultEditorItems 是分組陣列,攤平後即可直接沿用:

const slashItems = defaultEditorItems  .flat()  .filter((item): item is EditorSuggestionMenuItem =>    'kind' in item && typeof item.label === 'string'  )

API 參考

admin-editor-suggestion-menu

Props

名稱型別預設值說明
editor*Editor—tiptap Editor instance(必填)
handlers*EditorHandlers—handler map(必填):決定各 kind 選定後執行的行為,由呼叫端顯式傳入
items*EditorSuggestionMenuItem[] | EditorSuggestionMenuItem[][]—候選清單(可為扁平或分組陣列)
charstring | undefined"/"觸發字元,預設 `/`
pluginKeystring | undefined"editorSuggestionMenu"PM plugin key,預設 `editorSuggestionMenu`(同 editor 內多 menu 並存時 override)
limitnumber | undefined10顯示筆數上限,預設 10
filterFieldsstring[] | undefined["label"]filter 比對欄位,預設 `['label']`
ignoreFilterboolean | undefinedfalsetrue 時跳過內建 fuzzy filter(外部已 filter 時使用)
classClassValue——

* 代表必填

更新紀錄

  • feat: 新增 tiptap editor 元件系列273a0d0