/**
 * @file ChatComposerInput.tsx
 * @input Uses React, StyleX, useTriggerMenu, SearchSource
 * @output Exports ChatComposerInput rich input + trigger types
 * @position Core implementation; consumed by index.ts, ChatComposer;
 *   forwards DOM ref and exposes editor control via handleRef
 *
 * ContentEditable-based rich input for the chat composer.
 * Supports trigger menus (@ mentions, / commands) via SearchSource,
 * inline token rendering, serialization, Enter-to-submit with
 * IME-composition guarding and an onKeyDown seam for platform-specific
 * key handling, message history, paste/drop file handling, and
 * mobile-safe touch typography.
 *
 *
 * SYNC: When modified, update:
 * - /packages/core/src/Chat/index.ts
 * - /apps/storybook/stories/ChatComposer.stories.tsx
 * - /packages/cli/assets/templates/blocks/components/ChatComposerInput/ (block examples)
 */
import { type ReactNode, type KeyboardEvent, type ClipboardEvent } from 'react';
import type { BaseProps } from '../BaseProps';
import type { SearchableItem, SearchSource } from '../Typeahead/types';
import { type UseChatPasteAsTokenReturn } from './useChatPasteAsToken';
import { type BadgeProps } from '../Badge';
/** Imperative handle exposed by ChatComposerInput via handleRef */
export interface ChatComposerInputHandle {
    /** Insert a token (badge chip) at the current cursor position */
    insertToken: (token: ChatComposerToken) => string | undefined;
    /** Expand a token — replace the token span with its serialized text value */
    expandToken: (id: string) => void;
    /** Insert plain text at the current cursor position */
    insertText: (text: string) => void;
    /** Focus the input */
    focus: () => void;
    /** Get the current serialized value */
    getValue: () => string;
}
/** Badge config for the common case \u2014 structured, simple, autocomplete-friendly */
export type ChatComposerTokenBadge = {
    /** Serialized value \u2014 what this token becomes in the onSubmit string */
    value: string;
} & Omit<BadgeProps, 'ref' | 'xstyle' | 'className' | 'style'>;
/** Custom render for the escape hatch \u2014 tooltips, hovercards, rich content */
export type ChatComposerTokenCustom = {
    /** Serialized value \u2014 what this token becomes in the onSubmit string */
    value: string;
    /** Full control over the token\u2019s rendered content */
    render: () => ReactNode;
};
/**
 * Token inserted into the contentEditable by a trigger menu.
 *
 * Two forms:
 * - **Badge config** (recommended): `{ value, label, variant?, icon? }` \u2014
 *   renders an Badge. Structured, themeable, autocomplete-friendly.
 * - **Custom render**: `{ value, render }` \u2014 full control via ReactNode.
 *   Use for tooltips, hovercards, or any content beyond a badge.
 */
export type ChatComposerToken = ChatComposerTokenBadge | ChatComposerTokenCustom;
export type ChatComposerTriggerItem = SearchableItem;
export type ChatComposerTrigger = {
    /** Character that activates this trigger menu (e.g. '@', '/') */
    character: string;
    /**
     * Search source providing items for this trigger.
     * Reuses the same SearchSource interface as Typeahead \u2014
     * supports sync/async search, bootstrap, and cancel().
     *
     * Use `createStaticSource()` for static item lists,
     * or implement SearchSource for API-backed search.
     *
     * @example
     * ```
     * import {createStaticSource} from '@astryxdesign/core/Typeahead';
     * const mentionTrigger = {
     *   character: '@',
     *   searchSource: createStaticSource(users),
     *   onSelect: (item) => ({ value: `@${item.id}`, render: () => ... }),
     * };
     * ```
     */
    searchSource: SearchSource;
    /** How to render each item in the trigger menu */
    renderItem?: (item: SearchableItem) => ReactNode;
    /**
     * What to insert when an item is selected.
     * Return a string for plain text, or a Token for an inline chip.
     */
    onSelect: (item: SearchableItem) => string | ChatComposerToken;
    /**
     * Parse serialized tokens back into rendered tokens.
     * Used when loading a previous message for editing.
     */
    deserialize?: (value: string) => ChatComposerToken | null;
    /** Text shown when no results found. @default 'No results' */
    emptySearchResultsText?: string;
    /** Text shown during async search. @default 'Searching\u2026' */
    loadingText?: string;
    /** Accessible label for the menu. @default 'Suggestions' */
    menuLabel?: string;
};
export interface ChatComposerInputProps extends Omit<BaseProps<HTMLDivElement>, 'onChange' | 'onPaste' | 'onSubmit'> {
    /** Ref forwarded to the root element. */
    ref?: React.Ref<HTMLDivElement>;
    /** Imperative handle ref for programmatic control. */
    handleRef?: React.Ref<ChatComposerInputHandle>;
    /** Controlled value */
    value?: string;
    /** Change handler */
    onChange?: (value: string) => void;
    /** Placeholder text. @default 'Type a message\u2026' */
    placeholder?: string;
    /** Max rows before scrolling. @default 8 */
    maxRows?: number;
    /** Trigger definitions for @ menus, / commands, etc. */
    triggers?: ChatComposerTrigger[];
    /**
     * Debounce delay in ms before triggering async search.
     * Set to 0 for immediate search.
     * @default 150
     */
    debounceMs?: number;
    /** Enable message history recall. @default true */
    hasHistory?: boolean;
    /** Accessible label. @default 'Message input' */
    label?: string;
    /** Disabled state. @default false */
    isDisabled?: boolean;
    /** Paste handler. Called with the plain text before insertion. Return true to handle the paste yourself (e.g. insert a token instead). */
    onPaste?: (event: ClipboardEvent<HTMLDivElement>, text: string) => boolean | void;
    /**
     * Paste-as-token behavior. Defaults to converting pastes over 200 chars
     * into token chips. Pass a custom useChatPasteAsToken result to override,
     * or false to disable.
     */
    pasteAsToken?: UseChatPasteAsTokenReturn | false;
    /** File drop/paste handler */
    onFiles?: (files: File[]) => void;
    /** Submit handler (Enter without Shift) */
    onSubmit?: (value: string) => void;
    /**
     * Key-down handler invoked before the built-in Enter/history behavior
     * (but after an open trigger menu consumes the event).
     *
     * This is the seam for platform- or app-specific key handling:
     * - Call `event.preventDefault()` to suppress the default submit (e.g.
     *   let Enter insert a newline on a touch keyboard).
     * - Add behavior by acting on the event yourself (e.g. submit on
     *   Cmd/Ctrl+Enter) without calling `preventDefault()`, so the default
     *   handling still runs for other keys.
     *
     * IME composition is always respected regardless of this handler: Enter
     * never submits while a composition is in progress.
     */
    onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
}
export declare function ChatComposerInput(props: ChatComposerInputProps): import("react").JSX.Element;
export declare namespace ChatComposerInput {
    var displayName: string;
}
export declare function ChatComposerTokenElement({ token }: {
    token: ChatComposerToken;
}): import("react").JSX.Element;
export declare namespace ChatComposerTokenElement {
    var displayName: string;
}
//# sourceMappingURL=ChatComposerInput.d.ts.map