Tabbable

Maintain a consistent tab order for tabbable elements.

Loading...
Files
components/tabbable-demo.tsx
'use client';

import React from 'react';

import type { PlateElementProps } from '@udecode/plate-common/react';

import { cn } from '@udecode/cn';
import { Plate } from '@udecode/plate-common/react';
import { TabbablePlugin } from '@udecode/plate-tabbable/react';
import { useFocused, useSelected } from 'slate-react';

import { editorPlugins } from '@/components/editor/plugins/editor-plugins';
import { useCreateEditor } from '@/components/editor/use-create-editor';
import { tabbableValue } from '@/components/values/tabbable-value';
import { Editor, EditorContainer } from '@/components/plate-ui/editor';
import { PlateElement } from '@/components/plate-ui/plate-element';

export default function TabbableDemo() {
  const editor = useCreateEditor({
    plugins: [
      ...editorPlugins,
      TabbablePlugin.configure({
        node: { component: TabbableElement, isElement: true, isVoid: true },
      }),
    ],
    value: tabbableValue,
  });

  return (
    <Plate editor={editor}>
      <EditorContainer variant="demo">
        <Editor />
      </EditorContainer>
    </Plate>
  );
}

export function TabbableElement({ children, ...props }: PlateElementProps) {
  const selected = useSelected();
  const focused = useFocused();

  return (
    <PlateElement {...props}>
      <div
        className={cn(
          'mb-2 p-2',
          selected && focused
            ? 'border-2 border-blue-500'
            : 'border border-gray-200'
        )}
        contentEditable={false}
      >
        <p>This is a void element.</p>
        <button type="button">Button 1</button>{' '}
        <button type="button">Button 2</button>
      </div>
      {children}
    </PlateElement>
  );
}

功能特点

  • 确保编辑器中可 tab 切换元素之间的 tab 顺序一致。

安装

npm install @udecode/plate-tabbable

Usage

import { TabbablePlugin } from '@udecode/plate-tabbable/react';
 
const plugins = [
  // ...其他插件,
  TabbablePlugin,
];

与其他插件冲突

Tabbable 插件可能会与其他处理 Tab 键的插件(如:

  • 列表
  • 代码块
  • Indent 插件

使用 query 选项在 Tab 键应由其他插件处理时禁用 Tabbable 插件:

query: (editor) => {
  const inList = findNode(editor, { match: { type: ListItemPlugin.key } });
  const inCodeBlock = findNode(editor, { match: { type: CodeBlockPlugin.key } });
  return !inList && !inCodeBlock;
},

或者,如果你正在使用 Indent 插件,你可以只在选择特定类型的节点时启用 Tabbable 插件,例如 voids:

query: (editor) => !!findNode(editor, {
  match: (node) => isVoid(editor, node),
}),

非 void Slate 节点

一个 TabbableEntry 将创建每个可 tab 切换的 DOM 元素,使用 tabbable NPM 包确定。然后使用 isTabbable 过滤列表。

默认情况下,isTabbable 仅对 void Slate 节点内的entry返回 true。你可以覆盖 isTabbable 以添加对包含在其他类型 Slate 节点中的 DOM 元素的支持。

// Enable tabbable DOM elements inside CUSTOM_ELEMENT
isTabbable: (tabbableEntry) => (
  tabbableEntry.slateNode.type === CUSTOM_ELEMENT ||
  isVoid(editor, tabbableEntry.slateNode)
),

DOM elements outside the editor

在某些情况下,你可能希望允许用户从编辑器切换到渲染在编辑器之外的 DOM 元素,例如交互式弹出框。

要实现这一点,请覆盖 insertTabbableEntries 以返回 TabbableEntry 对象的数组,每个 DOM 元素一个,这些元素是你希望包含在可 tab 切换列表中的元素。TabbableEntryslateNodepath 应指向用户光标将位于的 Slate 节点,当 DOM 元素应可 tab 切换时。例如,如果 DOM 元素在链接被选中时出现,则 slateNodepath 应为链接的。

设置 globalEventListener 选项为 true 以确保 Tabbable 插件能够将用户的焦点返回到编辑器。

// Add buttons inside .my-popover to the list of tabbables
globalEventListener: true,
insertTabbableEntries: (editor) => {
  const [selectedNode, selectedNodePath] = getNodeEntry(editor, editor.selection);
 
  return [
    ...document.querySelectorAll('.my-popover > button'),
  ].map((domNode) => ({
    domNode,
    slateNode: selectedNode,
    path: selectedNodePath,
  }));
},

插件

TabbablePlugin

Options

Collapse all

    动态启用或禁用插件。默认返回 true

    • 默认值: () => true

    确定插件是否将其事件监听器添加到文档而不是编辑器,这允许它捕获来自编辑器外部的事件。

    • 默认值: false

    向可 tab 切换元素列表添加额外的entry。对于添加不在编辑器内的可 tab 切换元素很有用。它会忽略 isTabbable

    • 默认值: () => []

    确定一个元素是否应该包含在可 tab 切换列表中。如果 tabbableEntry 的 slateNode 是 void,则返回 true

    • 默认值: (tabbableEntry) => isVoid(editor, tabbableEntry.slateNode)

API

TabbableEntry

定义可 tab 切换entry的属性。

Attributes

Collapse all

    表示可 tab 切换entry的 HTML 元素。

    可 tab 切换entry对应的 Slate 节点。

    Slate 文档中 Slate 节点的路径。