Editor Toolbar
安裝
# 只依賴 @admin/editor-core;可搭 rich-editor 或 base editor 使用pnpm dlx shadcn-vue add @admin/editor-toolbarimport { AdminEditorToolbar, defaultEditorItems } from '@/registry/admin/ui/editor-toolbar'用法
最小可用組合:<AdminRichEditor> 容器內擺 <AdminEditorToolbar>(預設 layout 'fixed'),items 給 defaultEditorItems:
<script setup lang="ts">import type { JSONContent } from '@tiptap/core'import { ref } from 'vue'import { cn } from '@/lib/utils'import { baseProseClass } from '@/components/admin/editor'import { AdminEditorToolbar, defaultEditorItems } from '@/components/admin/editor-toolbar'import { AdminRichEditor, starterKitProseClass } from '@/components/admin/rich-editor'const value = ref<JSONContent | string>( '<h2>歡迎使用 admin-rich-editor</h2><p>這是一個 <strong>富文本編輯器</strong>,基於 <a href="https://tiptap.dev">tiptap</a> 並對齊 admin design tokens。</p><ul><li>項目一</li><li>項目二</li></ul>')// 預設只 bundle StarterKit;預設 toolbar 僅含 StarterKit 範圍能力,所有按鈕開箱即用</script><template> <admin-rich-editor v-slot="{ editor, handlers }" v-model="value" :ui="{ base: cn(baseProseClass, starterKitProseClass) }" > <admin-editor-toolbar :editor :handlers :items="defaultEditorItems" /> </admin-rich-editor></template>場景
Bubble layout
選取文字後浮現 toolbar(Notion / Medium 風)。設定 layout="bubble":
<script setup lang="ts">import type { JSONContent } from '@tiptap/core'import { ref } from 'vue'import { cn } from '@/lib/utils'import { baseProseClass } from '@/components/admin/editor'import { AdminEditorToolbar, defaultEditorItems } from '@/components/admin/editor-toolbar'import { AdminRichEditor, starterKitProseClass } from '@/components/admin/rich-editor'const value = ref<JSONContent | string>( '<p>選取一段文字試試看 — toolbar 會浮現在選取範圍上方(bubble 模式)。</p>')</script><template> <admin-rich-editor v-slot="{ editor, handlers }" v-model="value" :ui="{ base: cn(baseProseClass, starterKitProseClass) }" > <admin-editor-toolbar layout="bubble" :editor :handlers="handlers" :items="defaultEditorItems" /> </admin-rich-editor></template>Floating layout
游標停在空行時浮現(Notion 的 block 插入選單風格)。設定 layout="floating",items 只放區塊操作:
<script setup lang="ts">import type { JSONContent } from '@tiptap/core'import type { EditorToolbarItem } from '@/components/admin/editor-toolbar'import { IconBlockquote, IconList, IconListNumbers, IconSourceCode } from '@tabler/icons-vue'import { ref } from 'vue'import { cn } from '@/lib/utils'import { baseProseClass } from '@/components/admin/editor'import { AdminEditorToolbar } from '@/components/admin/editor-toolbar'import { AdminRichEditor, starterKitProseClass } from '@/components/admin/rich-editor'const value = ref<JSONContent | string>( '<p>在段尾按 Enter 產生空行,block menu 會浮現在該行(floating 模式)。</p>')// floating 的語意是「在空行插入區塊」,items 只放 block 操作const blockItems: EditorToolbarItem[][] = [ [ { label: '段落樣式', dropdownVariant: 'select', items: [ { kind: 'paragraph', label: '內文' }, { kind: 'heading', level: 1, label: '標題 1' }, { kind: 'heading', level: 2, label: '標題 2' } ] } ], [ { kind: 'blockquote', icon: IconBlockquote, label: '引言', tooltip: { text: '引言' } }, { kind: 'bulletList', icon: IconList, label: '項目清單', tooltip: { text: '項目清單' } }, { kind: 'orderedList', icon: IconListNumbers, label: '數字清單', tooltip: { text: '數字清單' } }, { kind: 'codeBlock', icon: IconSourceCode, label: '程式碼區塊', tooltip: { text: '程式碼區塊' } } ]]</script><template> <admin-rich-editor v-slot="{ editor, handlers }" v-model="value" :ui="{ base: cn(baseProseClass, starterKitProseClass) }" > <admin-editor-toolbar layout="floating" :editor :handlers="handlers" :items="blockItems" /> </admin-rich-editor></template>客製 items(精簡版)
:items 接受 EditorToolbarItem[](單列)或 EditorToolbarItem[][](分組,每組之間自動加 separator)。自寫 items 收緊功能:
<script setup lang="ts">import type { JSONContent } from '@tiptap/core'import type { EditorToolbarItem } from '@/components/admin/editor-toolbar'import { ref } from 'vue'import { cn } from '@/lib/utils'import { baseProseClass } from '@/components/admin/editor'import { AdminEditorToolbar } from '@/components/admin/editor-toolbar'import { AdminRichEditor, starterKitProseClass } from '@/components/admin/rich-editor'const value = ref<JSONContent | string>( '<p>只啟用 <strong>bold</strong> / <em>italic</em> / link 的精簡版,適合留言情境。</p>')// 客製 items:只保留留言情境會用到的功能const leanItems: EditorToolbarItem[][] = [ [ { kind: 'mark', mark: 'bold', tooltip: { text: '粗體' } }, { kind: 'mark', mark: 'italic', tooltip: { text: '斜體' } } ], [{ kind: 'link', tooltip: { text: '連結' } }]]</script><template> <admin-rich-editor v-slot="{ editor, handlers }" v-model="value" :starter-kit="{ heading: false, codeBlock: false, blockquote: false, horizontalRule: false }" :ui="{ base: cn(baseProseClass, starterKitProseClass) }" > <admin-editor-toolbar :editor :handlers="handlers" :items="leanItems" /> </admin-rich-editor></template>具名 slot 與 #item slot
item 可以整顆換成自訂元件:指定 slot: '<name>' 就交給同名具名 slot 渲染,沒指定的落到通用 #item slot。slot props 為 { item, index, isActive, isDisabled, onClick };不含 editor,需要就從外層 <AdminRichEditor v-slot="{ editor, handlers }"> 取。@admin/editor-text-color / @admin/editor-highlight 就是這樣接入的:
<script setup lang="ts">import type { JSONContent } from '@tiptap/core'import type { EditorToolbarItem } from '@/components/admin/editor-toolbar'import { IconLetterA } from '@tabler/icons-vue'import { Color } from '@tiptap/extension-color'import { TextStyle } from '@tiptap/extension-text-style'import { ref } from 'vue'import { cn } from '@/lib/utils'import { baseProseClass } from '@/components/admin/editor'import { AdminEditorTextColorButton, defaultColorSwatches} from '@/components/admin/editor-text-color'import { AdminEditorToolbar, defaultEditorItems } from '@/components/admin/editor-toolbar'import { AdminRichEditor, starterKitProseClass } from '@/components/admin/rich-editor'const value = ref<JSONContent | string>('<p>選取文字後,用 toolbar 最右側的 A 鈕設定文字顏色。</p>')// 文字顏色需自行注入官方 extension:Color 依賴 TextStyle,兩者都要const extensions = [TextStyle, Color]// color picker 為 kindless slot item:靠具名 slot 自畫,不綁 handlerconst items: EditorToolbarItem[][] = [ ...defaultEditorItems, [{ slot: 'color', icon: IconLetterA, label: '文字顏色', tooltip: { text: '文字顏色' } }]]</script><template> <admin-rich-editor v-slot="{ editor, handlers }" v-model="value" :extensions="extensions" :ui="{ base: cn(baseProseClass, starterKitProseClass) }" > <admin-editor-toolbar :editor :handlers="handlers" :items="items"> <!-- slot props 不含 editor;picker 從外層 v-slot 的 editor 取 --> <template #color> <admin-editor-text-color-button :editor="editor" :swatches="defaultColorSwatches" /> </template> </admin-editor-toolbar> </admin-rich-editor></template>defaultEditorItems
defaultEditorItems: EditorToolbarItem[][] 是預設工具列分組,只涵蓋 StarterKit 能力(復原、文字裝飾、段落樣式、區塊、Link),每個 item 都帶好 icon、繁中 label 與 tooltip。textAlign / image / indent 等非 StarterKit 能力由對應的 opt-in 包提供,spread 後追加即可:
const items = [ ...defaultEditorItems, [{ kind: 'insertVariable', name: 'username', label: '使用者名稱' }],]API 參考
組成
<template> <admin-rich-editor v-slot="{ editor, handlers }" v-model="value"> <admin-editor-toolbar :editor :handlers :items="defaultEditorItems" /> </admin-rich-editor></template>admin-editor-toolbar
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | — |
editor* | Editor | — | 一律由外部顯式傳入的 tiptap editor 實例 |
handlers* | EditorHandlers | — | merged handler map(必填):由呼叫端顯式傳入,決定各 kind 的 active / disabled / 執行 |
items* | A | — | — |
layout | EditorToolbarLayout | undefined | "fixed" | — |
* 代表必填
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
item | { item: NestedItem<A>; } & SlotExtraProps | — |
注意事項
- 不支援 SSR:bubble / floating layout 依賴瀏覽器 DOM 定位;元件殼不含
<ClientOnly>。Nuxt 請自行以<ClientOnly>包覆,其他 SSR 框架用等價機制;純 CSR 不需處理。見 安裝 · SSR。
更新紀錄
- feat: 新增 tiptap editor 元件系列273a0d0