/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { type NamedSignalsOutput } from '@lexical/extension'; import { type RefCountedRegistry } from 'lexical'; export type AriaPoliteness = 'polite' | 'assertive'; export type FocusTrapInitialFocus = 'firstFocusable' | 'container'; export interface FocusTrapOptions { /** * Where to land focus when the trap activates: * - `'firstFocusable'` (default): focus the first focusable descendant. * - `'container'`: focus the container itself. The container must * satisfy `tabIndex >= -1`; callers typically set `tabIndex={-1}` to * keep it out of the natural Tab order while remaining programmatically * focusable. Use for dialogs whose first focusable is a dismiss/close * action so the user lands on the dialog body and screen readers * announce the dialog label before any control. */ initialFocus?: FocusTrapInitialFocus; /** * Predicate that exempts an element from the pull-back. When it * returns `true` for `event.target`, the focusin handler lets focus * stay outside the container. Useful for portaled panels (e.g. * autocomplete popups) that live outside the trap container yet * logically belong to it. */ allowOutside?: (target: HTMLElement) => boolean; } export type RovingOrientation = 'horizontal' | 'vertical' | 'both'; export interface RovingTabIndexOptions { /** * Which arrow keys move focus. * - `horizontal` (default): ArrowLeft / ArrowRight * - `vertical`: ArrowUp / ArrowDown * - `both`: any arrow key */ orientation?: RovingOrientation; /** * Selector for the group's roving items. The default matches direct-child * non-disabled buttons. Pass a custom selector to include other focusables * or to scope to a marker attribute (e.g. `[data-roving-item]`). */ itemSelector?: string; } export interface FocusManagerOptions { /** * Selector used to find the toolbar's first focusable item when * activating via the shortcut. Defaults to non-disabled direct-child * buttons (the same scope used by `registerRovingTabIndex`), so the * active roving item naturally receives focus. */ toolbarItemSelector?: string; } export interface AriaLiveRegionExtensionConfig { /** {@link AriaPoliteness} for the mounted region. */ politeness: AriaPoliteness; /** * Owner element to append the live region to. `null` falls back to * `document.body`; an explicit element keeps the region in the same * accessibility subtree as the editor (shadow root or portaled overlay). */ owner: HTMLElement | null; } /** * Public output of {@link AriaLiveRegionExtension}. The `politeness` and * `owner` config values are exposed as runtime-tunable signals — setting * `politeness` updates the mounted region's `aria-live`, setting `owner` * re-mounts the region — alongside a stable `announce` sink that is valid for * the editor's lifetime (callers never see the region element or its disposal). */ export type AriaLiveRegion = NamedSignalsOutput & { /** * Write a message into the editor's live region. Announcing the same * string back-to-back appends a zero-width space so screen readers * register the change and re-announce. A no-op until a region is mounted * (the editor has a root element, or an `owner` is configured). */ announce: (message: string) => void; }; /** * Platform-independent extension that owns a single `aria-live` region for * the editor and exposes a stable {@link AriaLiveRegion} sink as its output. * Other a11y extensions (`HistoryAnnounceExtension`, * `EditorModeAnnounceExtension`) depend on it and announce through * `output.announce`. * * The sink writes to a private `message` signal created in `init`. The * `politeness` / `owner` config are exposed as signals (via `namedSignals`). * `register` tracks the editor's root element reactively and runs three * effects: one creates / disposes the region element as the root document (or * `owner`) changes, one applies the current `politeness` to the mounted region, * and one mirrors the current message into it. Buffering through signals * decouples the stable `announce` (from `build`) from the region element — * which comes and goes with the root — and creates the region in the editor's * own document (e.g. an iframe-portaled editor) rather than the top-level * `document`. */ export declare const AriaLiveRegionExtension: import("lexical").LexicalExtension>; export interface HistoryAnnounceExtensionConfig { /** Message announced after an undo. */ undone: string; /** Message announced after a redo. */ redone: string; /** When `true`, undo / redo are not announced. Toggle at runtime via the * output signal. Default `false`. */ disabled: boolean; } /** * Platform-independent extension that announces undo / redo through the * `AriaLiveRegionExtension`'s shared sink. */ export declare const HistoryAnnounceExtension: import("lexical").LexicalExtension, unknown>; export interface EditorModeAnnounceExtensionConfig { /** Message announced when the editor becomes editable. */ editable: string; /** Message announced when the editor becomes read-only. */ readOnly: string; /** When `true`, editable / read-only transitions are not announced. Toggle * at runtime via the output signal. Default `false`. Announcements are * transition-based (like the initial mount, which is silent), so toggling * `disabled` back to `false` while the editor is already read-only does not * re-announce the current mode — the next `setEditable` transition does. */ disabled: boolean; } /** * Platform-independent extension that announces * `editor.setEditable(true|false)` transitions through the * `AriaLiveRegionExtension`'s shared sink. */ export declare const EditorModeAnnounceExtension: import("lexical").LexicalExtension, unknown>; /** * The public output of the focus-trap, roving-tabindex and focus-manager * extensions: register a container (reference counted) and get back an * idempotent disposer. Callers register through this method instead of a * mutable map and never see the container bookkeeping. It is the core * {@link RefCountedRegistry} keyed by `HTMLElement`. * * Each extension creates the registry in `build` (where the editor is * available for the per-container activation) and disposes it on `register` * teardown via {@link RefCountedRegistry.dispose}. */ export type ContainerRegistry = RefCountedRegistry; /** * Platform-independent extension that traps Tab / Shift+Tab focus inside one * or more containers. Register a container through the extension output * ({@link ContainerRegistry.register}); the React adapter is * `useLexicalFocusTrapRef` from `@lexical/react`. */ export declare const FocusTrapExtension: import("lexical").LexicalExtension, unknown>; /** * Platform-independent extension that wires the WAI-ARIA roving-tabindex * pattern on one or more containers. Register a container through the * extension output ({@link ContainerRegistry.register}); the React adapter is * `useLexicalRovingTabIndexRef` from `@lexical/react`. */ export declare const RovingTabIndexExtension: import("lexical").LexicalExtension, unknown>; /** * Platform-independent extension that wires the editor-to-toolbar focus jump * (Alt+F10 / Escape return) on one or more toolbars. Register a toolbar * through the extension output ({@link ContainerRegistry.register}); the React * adapter is `useLexicalFocusManagerRef` from `@lexical/react`. */ export declare const FocusManagerExtension: import("lexical").LexicalExtension, unknown>;