添加下拉菜单以选择列表类型
Available for free
一个用于从多种列表类型中选择的下拉菜单。
安装
通过 Tiptap CLI 添加该组件:
npx @tiptap/cli@latest add list-dropdown-menu组件
<ListDropdownMenu />
一个预构建的 React 组件,提供一个下拉菜单,用于选择不同的列表类型。
使用示例
import { EditorContent, EditorContext, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { TaskList } from '@tiptap/extension-task-list'
import { TaskItem } from '@tiptap/extension-task-item'
import { ListDropdownMenu } from '@/components/tiptap-ui/list-dropdown-menu'
import '@/components/tiptap-node/code-block-node/code-block-node.scss'
import '@/components/tiptap-node/list-node/list-node.scss'
import '@/components/tiptap-node/paragraph-node/paragraph-node.scss'
export default function MyEditor() {
const editor = useEditor({
immediatelyRender: false,
extensions: [StarterKit, TaskList, TaskItem.configure({ nested: true })],
content: `
<ul>
<li>
<strong>粗体</strong> 用于强调,可以使用 <code>**</code> 或 <code>⌘+B</code> 或 <code>B</code> 按钮。
</li>
<li>
<em>斜体</em> 用于细微的差别,可以使用 <code>*</code> 或 <code>⌘+I</code> 或 <code>I</code> 按钮。
</li>
<li>
<s>删除线</s> 用于显示修改,可以使用 <code>~~</code> 或 <code>~~S~~</code> 按钮。
</li>
</ul>
<ul data-type="taskList">
<li data-type="taskItem" data-checked="true">
<div>
测试模板
</div>
</li>
<li data-type="taskItem" data-checked="false">
<div>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://tiptap.dev/pricing">创建帐户</a>
</div>
</li>
<li data-type="taskItem" data-checked="false">
<div>
下载免费模板
</div>
</li>
</ul>
`,
})
return (
<EditorContext.Provider value={{ editor }}>
<ListDropdownMenu
editor={editor}
types={['bulletList', 'orderedList', 'taskList']}
hideWhenUnavailable={true}
portal={false}
onOpenChange={(isOpen) => console.log('Dropdown opened:', isOpen)}
/>
<EditorContent editor={editor} role="presentation" />
</EditorContext.Provider>
)
}属性
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| editor | Editor | null | null | Tiptap 编辑器实例 |
| types | Array<'bulletList' | 'orderedList' | 'taskList'> | ['bulletList', 'orderedList', 'taskList'] | 下拉菜单中包含的列表类型 |
| hideWhenUnavailable | boolean | false | 当没有可用列表类型时是否隐藏菜单 |
| onOpenChange | (isOpen: boolean) => void | - | 下拉菜单打开状态变化时的回调函数 |
| portal | boolean | false | 是否在 Portal 中渲染下拉菜单 |
Hooks
useListDropdownMenu()
一个自定义 Hook,用于管理列表下拉菜单的状态并确定可用的选项。
使用示例
import { useListDropdownMenu } from '@/components/tiptap-ui/list-dropdown-menu'
import { ListButton } from '@/components/tiptap-ui/list-button'
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
} from '@/components/tiptap-ui-primitive/dropdown-menu'
import { ButtonGroup } from '@/components/tiptap-ui-primitive/button'
function MyListDropdown() {
const { filteredLists, canToggle, isActive, isVisible, Icon, activeType } = useListDropdownMenu({
editor,
types: ['bulletList', 'orderedList', 'taskList'],
hideWhenUnavailable: true,
})
if (!isVisible) return null
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button disabled={!canToggle}>
<Icon />
列表 {isActive ? '(激活)' : ''}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<ButtonGroup>
{filteredLists.map((option) => (
<DropdownMenuItem key={option.type} asChild>
<ListButton editor={editor} type={option.type} text={option.label} />
</DropdownMenuItem>
))}
</ButtonGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}属性
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| editor | Editor | null | undefined | Tiptap 编辑器实例 |
| types | ListType[] | ["bulletList", "orderedList", "taskList"] | 要显示在下拉菜单中的列表类型数组 |
| hideWhenUnavailable | boolean | false | 是否在没有可用列表类型时隐藏下拉菜单 |
返回值
| 名称 | 类型 | 描述 |
|---|---|---|
| isVisible | boolean | 下拉菜单是否应该显示 |
| activeType | ListType | undefined | 当前激活的列表类型 |
| isActive | boolean | 是否有列表类型当前处于激活状态 |
| canToggle | boolean | 是否可以切换任何列表类型 |
| types | ListType[] | 配置中的列表类型数组 |
| filteredLists | ListOption[] | 根据可用类型过滤后的列表选项数组 |
| label | string | 下拉菜单的辅助功能文本标签 |
| Icon | React.FC | 用于当前激活列表类型或默认图标的组件 |
工具函数
canToggleAnyList(editor, listTypes)
检查指定的列表类型中是否有任何可以在当前编辑器状态下切换的。
import { canToggleAnyList } from '@/components/tiptap-ui/list-dropdown-menu'
const canToggle = canToggleAnyList(editor, ['bulletList', 'orderedList'])
if (canToggle) {
console.log('至少有一种列表类型可以切换')
}参数
| 名称 | 类型 | 描述 |
|---|---|---|
| editor | Editor | null | Tiptap 编辑器实例 |
| listTypes | ListType[] | 要检查的列表类型数组 |
返回值
boolean - 是否至少有一种列表类型可以切换。
isAnyListActive(editor, listTypes)
检查指定的列表类型中是否有任何当前处于激活状态的。
import { isAnyListActive } from '@/components/tiptap-ui/list-dropdown-menu'
const isActive = isAnyListActive(editor, ['bulletList', 'orderedList', 'taskList'])
if (isActive) {
console.log('至少有一种列表类型当前处于激活状态')
}参数
| 名称 | 类型 | 描述 |
|---|---|---|
| editor | Editor | null | Tiptap 编辑器实例 |
| listTypes | ListType[] | 要检查的列表类型数组 |
返回值
boolean - 是否至少有一种列表类型当前处于激活状态。
getFilteredListOptions(availableTypes)
根据可用类型过滤预定义的列表选项。
import { getFilteredListOptions } from '@/components/tiptap-ui/list-dropdown-menu'
const availableOptions = getFilteredListOptions(['bulletList', 'taskList'])
// 只返回项目符号列表和任务列表的选项参数
| 名称 | 类型 | 描述 |
|---|---|---|
| availableTypes | ListType[] | 要包含的列表类型数组 |
返回值
ListOption[] - 过滤后的列表选项数组。
getActiveListType(editor, availableTypes)
获取可用类型中当前激活的列表类型。
import { getActiveListType } from '@/components/tiptap-ui/list-dropdown-menu'
const activeType = getActiveListType(editor, ['bulletList', 'orderedList', 'taskList'])
console.log('当前列表类型:', activeType)参数
| 名称 | 类型 | 描述 |
|---|---|---|
| editor | Editor | null | Tiptap 编辑器实例 |
| availableTypes | ListType[] | 要检查的列表类型数组 |
返回值
ListType | undefined - 当前激活的列表类型,如果没有激活则为 undefined。
快捷键
每个列表类型支持以下快捷键(继承自底层的 ListButton 组件):
- Cmd/Ctrl + Shift + 8:切换项目符号列表
- Cmd/Ctrl + Shift + 7:切换有序列表
- Cmd/Ctrl + Shift + 9:切换任务列表
当编辑器的 schema 中包含对应的列表类型时,这些快捷键会自动注册。
依赖
@tiptap/react— 核心 Tiptap React 集成@tiptap/starter-kit— 包含列表支持的基础扩展包@tiptap/extension-task-list— 任务列表扩展@tiptap/extension-task-item— 任务项扩展
参考组件
use-tiptap-editor(hook)list-button(组件)button(基础组件)dropdown-menu(基础组件)card(基础组件)tiptap-utils(工具库)chevron-down-icon(图标)list-icon(图标)list-ordered-icon(图标)list-todo-icon(图标)