/**
* The reference mention plugin — `@[label](id)` mentions as native chips.
*
* The proving consumer of the P3 plugin API (#156): one plugin wires all
* three surfaces together —
*
* - **parser**: `@[label](id)` parses to an `extension` node (streaming-safe:
* a half-typed `@[lab` stays literal text),
* - **editor field**: the node maps to a `mention` span over a single
* U+FFFC (the chip invariant — see `InlineSpanType` in lynx-richtext),
* rendered natively as a pill; selecting a suggestion inserts the chip
* via `controller.insertChip`, replacing the typed trigger run,
* - **markdown out**: the span serializes back to `@[label](id)` from its
* attrs (the covered text is the U+FFFC, never the label).
*
* v1 label rule: `]`, `)`, and CR/LF are forbidden in both labels and ids —
* the serializer strips them and the parser regex doesn't match them, so
* round-trips are idempotent by construction.
*
* A factory (not a constant) because the consumer supplies the candidate
* source:
*
* ```tsx
* const mentions = createMentionPlugin({
* search: (q) => users.filter((u) => u.label.toLowerCase().startsWith(q.toLowerCase())),
* });
*
* ```
*/
import type { JSXElement } from '@sigx/lynx';
import type { ParserInlineExtension } from '../parser/extensions.js';
import type { ExtensionProps, MarkdownChild } from '../render/components.js';
import type { MarkdownEditorPlugin, TriggerItem } from '../editor/plugin.js';
export interface MentionCandidate {
id: string;
label: string;
kind?: string;
/**
* Extra **display-only** fields (e.g. `avatar`, `subtitle`) — carried
* through to the suggestion row's `renderItem` as `item.` for a
* richer popup UI. They never reach the chip payload or the serialized
* markdown (only `id`/`label`/`kind` do), so they can hold anything the row
* needs without affecting round-tripping.
*/
[key: string]: unknown;
}
export interface MentionPluginOptions {
/** Resolve candidates for the typed query (sync or async). */
search(query: string): MentionCandidate[] | Promise;
/** Re-skin a suggestion row in the popup. */
renderItem?(item: TriggerItem, active: boolean): JSXElement;
/**
* Preview-pill renderer, exposed as `plugin.inline.component`.
* `MarkdownView` is not plugin-aware — wire it up explicitly:
* `components={{ extension: { mention: plugin.inline.component } }}`
* (with `extensions={[mentionSyntax]}`).
*/
component?: (props: ExtensionProps) => MarkdownChild;
/** Popup trigger char (the markdown syntax stays `@[label](id)`). Default `'@'`. */
trigger?: string;
/** Debounce between `search` calls in ms. */
debounce?: number;
}
/** The parser extension for `@[label](id)` (exported for MarkdownView previews). */
export declare const mentionSyntax: ParserInlineExtension;
export declare function createMentionPlugin(options: MentionPluginOptions): MarkdownEditorPlugin;