字体族组合框

Available in Start plan

适用于 Tiptap 编辑器的可搜索字体族选择器。触发器会显示当前激活的字体;展开后会出现一个模糊搜索字段,以及按类别分组的字体,每种字体都以其自身字形进行预览。“默认字体”选项会取消任何内联字体设置。

它是 font-family-dropdown-menu 的一个更丰富、可搜索的对应组件,并与 @tiptap/extension-text-style 中的 FontFamily 标记配合使用。该组件与字体目录无关:你可以传入自己的 fontscategoriesdefaultFont,也可以使用内置的网页安全默认值。所有编辑器逻辑都位于 useFontFamilyCombobox 钩子中。

安装

通过 Tiptap CLI 添加该组件:

npx @tiptap/cli@latest add font-family-combobox

组件

<FontFamilyCombobox />

一个基于 Ariakit 的 menu-with-combobox 复合组件预构建的可搜索字体选择器。

用法

export default function MyEditor() {
  return (
    <FontFamilyCombobox
      editor={editor}
      hideWhenUnavailable={true}
      onOpenChange={(isOpen) => console.log('选择器', isOpen ? '已打开' : '已关闭')}
    />
  )
}

要使用你自己的目录,请提供 fontscategoriesdefaultFont。每个选项的 category 会与某个分类的 id 匹配,而选项可选的 fallbackFor 允许导入的系统字体(例如 "Arial")解析为某个打包的字体族。

const fonts = [
  { value: 'inter', label: 'Inter', family: 'Inter', hint: 'UI 无衬线', category: 'sans-serif', default: true },
  { value: 'georgia', label: 'Georgia', family: 'Georgia, serif', hint: '衬线', category: 'serif' },
]
const categories = [
  { id: 'sans-serif', label: '无衬线' },
  { id: 'serif', label: '衬线' },
]

<FontFamilyCombobox editor={editor} fonts={fonts} categories={categories} defaultFont={fonts[0]} />

属性

该组件还会将任何额外的 Button 属性(type 除外)透传给触发器。

名称类型默认值描述
editorEditor | nullundefinedTiptap 编辑器实例。
fontsFontFamilyOption[]defaultFontFamilyOptions在选择器中提供的字体。
defaultFontFontFamilyOptiondefaultFontFamilyOption当未应用任何行内字体时,文档所回退使用的字体。
categoriesFontFamilyCategory[]defaultFontFamilyCategories要渲染的分类组,与每个字体的 category 匹配。
hideWhenUnavailablebooleanfalse当无法应用字体族时隐藏选择器。
onOpenChange(boolean) => voidundefined选择器打开或关闭时的回调。

类型

interface FontFamilyOption {
  label: string // 选择器中的显示名称
  value: string // 稳定标识符
  family: string // 应用于文档的 CSS font-family;此字体会用于预览
  hint?: string // 标签下方的简短描述,例如 "类似 Calibri"
  category: string // 组 id(与 FontFamilyCategory 匹配)
  default?: boolean // 标记默认选项(无行内字体)
  fallbackFor?: string[] // 导入时此字体族可替代的系统字体
}

interface FontFamilyCategory {
  id: string
  label: string
}

Hooks

useFontFamilyCombobox()

一个无界面(headless)的 Hook,暴露构建自定义字体选择器所需的选择状态和操作。

用法

function MyFontPicker() {
  const { isVisible, triggerLabel, selectFont, selectDefault, filterFonts } = useFontFamilyCombobox(
    { editor, hideWhenUnavailable: true },
  )

  if (!isVisible) return null

  const results = filterFonts('geo') // 搜索查询的排序匹配结果
  // …使用 selectFont(font) / selectDefault() 渲染你自己的 UI
}

属性

名称类型默认值描述
editorEditor | nullundefinedTiptap 编辑器实例。
fontsFontFamilyOption[]defaultFontFamilyOptions要提供的字体。
defaultFontFontFamilyOptiondefaultFontFamilyOption当未设置任何内联字体时,文档的回退字体。
hideWhenUnavailablebooleanfalse当字体族不可用时隐藏选择器。

返回值

名称类型描述
isVisibleboolean选择器是否应当渲染。
canToggleboolean当前状态下是否可以应用字体族。
isActiveboolean是否有显式的内联字体处于激活状态(不是默认字体)。
fontsFontFamilyOption[]已配置的字体。
defaultFontFontFamilyOption已配置的默认字体。
selectionStateFontFamilySelectionState选择内容的字体状态(default / font / mixed)。
activeFontFamilystring应用于所选内容的 font-family(默认时为空)。
activeFontFontFamilyOption | undefined当前字体族对应的已解析选项(如果有)。
triggerLabelstring触发器标签(当前字体、Mixed,或 Default · …)。
selectFont(font: FontFamilyOption) => void将字体族应用到所选内容。
selectDefault() => void取消设置任何内联字体(使用文档默认字体)。
filterFonts(query: string) => FontFamilyOption[]根据搜索查询对已配置字体进行排序。

实用工具

默认字体目录

import {
  defaultFontFamilyOptions,
  defaultFontFamilyCategories,
  defaultFontFamilyOption,
} from '@/components/tiptap-ui/font-family-combobox'

一组适合网页使用的字体(Arial、Verdana、Tahoma、Times New Roman、Georgia、Courier New),按无衬线 / 衬线 / 等宽分组,因此无需加载任何 webfont 即可开箱即用。

辅助函数

import {
  filterFontsByQuery,
  findFontByFamily,
  resolveFontFamily,
  getActiveFontOption,
  getFontFamilySelectionState,
  getFontFamilyTriggerLabel,
} from '@/components/tiptap-ui/font-family-combobox'

filterFontsByQuery(fonts, 'geo') // 排名匹配(空查询 → 顺序不变)
findFontByFamily(fonts, 'Georgia') // family 匹配的选项,或 undefined
resolveFontFamily(fonts, 'Arial') // 通过每个选项的 fallbackFor 将系统字体映射过去
getActiveFontOption(fonts, 'Inter') // 将已应用的 family 解析为一个选项
getFontFamilySelectionState(editor) // { kind: 'default' | 'font' | 'mixed', fontFamily }
getFontFamilyTriggerLabel(state, defaultFont, fonts) // 触发器标签字符串

要求

依赖项

  • @tiptap/react — Tiptap React 核心集成
  • @tiptap/pm — 用于读取选区字体标记的 ProseMirror 模型/状态
  • match-sorter — 用于搜索字段的模糊排序
  • @tiptap/extension-text-style — 提供此选择器应用的 FontFamily 标记

引用的组件

  • use-tiptap-editor(hook)
  • use-composed-ref(hook)
  • font-family-dropdown-menu(组件 — 共享编辑器辅助工具)
  • button(基础组件)
  • combobox(基础组件)
  • input(基础组件)
  • menu(基础组件)
  • check-icon(图标)
  • chevron-down-icon(图标)