import React from 'react'; import { type AparteConfig, type AparteChatImperativeApi } from '@aparte/core'; import type { AparteMessage, AparteSendEventDetail, AparteActionEventDetail } from '../types.js'; export interface AparteChatProps { /** * The host element's `id`, and therefore the `targetId` every event this chat * dispatches carries. * * Generated when omitted, which is the right default — but it used to be * generated and neither accepted nor exposed, so * `AparteClientOptions.scopeToTargetId` (the documented way to run several * independent clients on one page) was unreachable from this component: there * was no way to learn the id the client had to match. Angular exposed it; React, * Vue and Svelte did not. */ id?: string; /** * Messages on the active path. **Optional** — omit for an uncontrolled chat * that starts empty (defaults to `[]`); pass it together with * `onMessagesChange` to control the list from the parent. */ messages?: AparteMessage[]; placeholder?: string; disabled?: boolean; isTyping?: boolean; typingText?: string; /** When false, Shift+Enter submits and a bare Enter inserts a newline. */ submitOnEnter?: boolean; /** Freeze viewport spacer recalculation for this many ms after a conv swap. */ layoutTransitionMs?: number; /** * Opt in to the "centered composer when empty" layout: while the message * list is empty the composer sits vertically centered with the `emptyState` * content above it, then slides to the bottom on the first message (~0.3s). * Off by default — purely additive: adds the `aparte-chat-container--auto-center` * modifier + a `data-aparte-empty` attribute that the shipped `aparte.css` recipe * keys off. No effect unless you also render an `emptyState`. */ centerWhenEmpty?: boolean; /** * The conversation is on its way: the viewport draws two skeleton turns, the empty * state stays off and the composer is disabled until it lands. The conversation * controller sets this itself while it fetches through your adapter's `loadFull()`; * the prop is for a wait of your own. Off by default. */ loading?: boolean; /** * Overlay the composer on the transcript (the ChatGPT anatomy): the scroll * surface spans the whole column, the scrollbar runs edge to edge, and the * composer floats over it. Core measures the floating stack and keeps content, * spacer and the scroll button clear of it. Read when the viewport mounts. */ overlayComposer?: boolean; /** * Add the file picker + chips strip to the default composer shell. **Off by * default**, because the capability needs a host that consumes the files: an * `AparteClient` inlines them per its `rawFileInject` option, but if you drive * your own loop you must read `event.files` in `onMessageSent` — otherwise the * file the user deliberately attached is dropped in silence. No effect when you * pass your own `composer` (drop `` and * `` in it yourself). */ attachments?: boolean; /** * Render the `` presenter inside the host — **on by default**, * as it is in ``: the built-in approval gate and `requestUserInput()` * ask through it, and it renders nothing until something asks. Pass `false` when * you mount a presenter of your own (`setElicitationPresenter`) or place the element * yourself. The first consumer to hit this appended the element by hand next to the * React tree, guided by a warning that named an `` this wrapper does not * render. */ elicitation?: boolean; /** Extra class names for the root element (`[data-aparte-chat]`), merged after core's own. */ className?: string; /** Inline style for the root element (`[data-aparte-chat]`). */ style?: React.CSSProperties; /** * Active conversation id. When set, the wrapper loads/persists via the * `AparteConversationManager` registered in `aparteGlobalConfig` (set `null` to deselect). */ conversationId?: string | null; /** * Custom composer content, rendered inside `` in place of the * default shell (input · send, plus the attachment primitives when * `attachments` is set). Compose the headless * `aparte-composer-*` primitives freely — e.g. a skin-specific layout. Omit for * the default shell. The `` element (and its placeholder / * disabled / submit-on-enter behaviour) is always provided by the wrapper. */ composer?: React.ReactNode; /** * Render your OWN element per message in place of ``. * Opt-in — omit for the default bubble. The returned node is driven by the * reactive message list, so it updates live during streaming (no need to * implement any imperative interface): re-render from `message.content` / * `message.segments`. Note the built-in action bar (retry/edit/branch) and * the imperative streaming push are the native bubble's — a custom bubble * owns whatever it wires (it can dispatch `aparte-retry` etc. or call the * wrapper's imperative API). */ renderBubble?: (message: AparteMessage) => React.ReactNode; /** * Welcome / placeholder content shown INSIDE the viewport while there are no * messages (a real "empty state" region, not a workaround via `aboveComposer`). * Replaced by the message list on the first message. */ emptyState?: React.ReactNode; /** * Content rendered ABOVE the composer (e.g. a disclaimer banner, a * "scroll to bottom" affordance, a context chip). Ignored when a full * custom `composer` replaces the shell. */ aboveComposer?: React.ReactNode; /** * The composer's bottom row — a mode picker, a model selector, a token counter. * Rendered inside core's ``; nothing is rendered at all * when you pass nothing, so an unused row never draws its separator. * * **Placement is the DOM order.** There is no left/center/right slot: put things in * the order you want them, and push a control (with everything after it) to the end * with `margin-inline-start: auto`. That is a logical property, so the row reads * correctly in a right-to-left locale with no extra work. * * Ignored when a full custom `composer` replaces the shell. * * @example * * * * } * /> */ toolbar?: React.ReactNode; /** * Notification that the user submitted a message from the composer. The * user's message is **appended to the thread automatically** (optimistic UI) * before this fires — do NOT add it again here. In an uncontrolled chat, * appending it duplicates it; in a controlled chat, mirror it into your own * `messages`. Use this for side-effects: scroll, analytics, backend send. */ onMessageSent?: (event: AparteSendEventDetail) => void; /** * Fired when a custom bubble action (registered via * `aparteGlobalConfig.registerAction` with `zones: ['bubble']`) is clicked — a typed * wrapper over the bubbling `aparte-action` DOM event. Dispatch on `detail.actionId`. */ onAction?: (detail: AparteActionEventDetail) => void; /** * Fired when the active message path changes (branch navigation / edit / * retry / streaming). Set the result back as the `messages` prop. */ onMessagesChange?: (messages: AparteMessage[]) => void; /** Fired when a message is appended internally (e.g. by AparteClient). */ onMessageAppended?: (message: AparteMessage) => void; /** Fired when the typing/"thinking" indicator should toggle. */ onTypingChange?: (isTyping: boolean) => void; /** Fired when the controller lazily creates a conversation on first send. */ onConversationCreated?: (id: string) => void; /** * Instance {@link AparteConfig} for this chat. When set, every aparté * component rendered inside resolves THIS config instead of the global * `aparteGlobalConfig` — letting several independently-configured chats * (different providers, tools, renderers) coexist on one page. Omit for the * global config. Read once when the host mounts. */ config?: AparteConfig; } export declare const AparteChat: React.ForwardRefExoticComponent>; //# sourceMappingURL=AparteChat.d.ts.map