FieldChat

Поле чата поверх FieldTextArea. Многострочный ввод с автоматическим ростом высоты (1–4 строки), футером действий (прикрепление файлов и отправка) и списком прикреплённых вложений. Enter отправляет сообщение, Shift+Enter переносит строку. Прикреплённые файлы на desktop показываются под полем, на mobile — над ним.

Когда использовать

  • Поле ввода сообщения в чате или диалоге с ассистентом.
  • Нужно прикрепление файлов рядом с вводом и отправка по Enter.

Когда не нужен FieldChat:

  • Многострочное описание сущности без отправки/вложений — FieldDescription.
  • Произвольный многострочный текст — FieldTextArea.

Анатомия

Ввод

FieldTextArea с minRows=1 и maxRows=4: поле растёт по мере набора текста и дальше скроллится. Плейсхолдер берётся из локали.

Футер действий

  • Скрепка (FileUpload) — прикрепление файлов; видна только при переданном attachment. Тип допустимых файлов задаётся через attachment.accept.
  • Кнопка отправки — активна, когда есть непустой текст или хотя бы один файл; иначе disabled.

Вложения

attachment.files рендерятся карточками: AttachmentSquare на desktop, полноширинный Attachment на mobile. Удаление — через attachment.onFileDelete.

Клавиатура

  • Enter — отправка (вызывает handleSubmit(value)), если ввод валиден.
  • Shift+Enter — перенос строки без отправки.

Примеры использования

Базовый

БазовыйМногострочный ввод с отправкой по Enter.
tsx
import { FieldChat } from '@cloud-ru/ds-uikit-product-fields-predefined';
import { useState } from 'react';

export function FieldChatBasic() {
  const [value, setValue] = useState('');

  return <FieldChat value={value} onChange={setValue} handleSubmit={() => setValue('')} />;
}

С вложениями

С вложениямиПрикрепление и удаление файлов, отправка очищает поле и список.
tsx
import { FieldChat } from '@cloud-ru/ds-uikit-product-fields-predefined';
import { useState } from 'react';

export function FieldChatWithAttachments() {
  const [value, setValue] = useState('');
  const [files, setFiles] = useState<File[]>([]);

  return (
    <FieldChat
      value={value}
      onChange={setValue}
      handleSubmit={() => {
        setValue('');
        setFiles([]);
      }}
      attachment={{
        files,
        accept: 'image/*,.pdf',
        onFilesUpload: uploaded => setFiles(prev => [...prev, ...uploaded]),
        onFileDelete: file => setFiles(prev => prev.filter(item => item !== file)),
      }}
    />
  );
}

Props

Types

PropsFieldChatProps
PropTypeDefaultRequiredDescription
allowMoreThanMaxLengthbooleantruenoРазрешить ввод свыше `maxLength` символов (счётчик продолжит расти).
attachment(Pick<FileUploadProps, "accept" | "onFilesUpload"> & { files?: File[]; onFileDelete: ((file?: File) => void) | undefined; }) | undefinednoПрикрепление файлов
autoFocusbooleannoАвтофокус. На mobile выключается адаптивно (см. `layoutPresets`)
backgroundbooleantruenoФон поля (acrylic)
captionstringnoВторичная подпись справа
classNamestringnoCSS-класс CSS-класс корня `FieldDecorator`
data-test-idstringno
defaultValuestringnoНачальное значение (uncontrolled-режим)
disabledbooleannoПоле выключено
errorstringnoОшибка (приоритетнее `hint`; форсит `validationState=error`)
fieldClassNamestringnoCSS-класс оболочки поля
handleSubmit(value: string) => voidyesКолбек действия при отправке
headerReactNodenoНода над textarea — ряд элементов до контента (Figma `elementWrapperBefore` / `slotBeforeContent`): тулбар с кнопками, чипами и т.п.
idstringnoHTML id
innerRefRef<HTMLDivElement>noRef на корневой DOM-элемент
inputMode"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url"noРежим виртуальной клавиатуры (`inputmode` нативного `<textarea>`)
labelForstringnoHTML-атрибут `for` для `<label>`
labelTooltipQuestionTooltipPropsnoПодсказка (question-tooltip) у заголовка
layoutPresetsPartial<Record<LayoutType, Partial<{ autoFocus: boolean; }>>>noПереопределение адаптивных дефолтов по раскладке. Участвует `autoFocus`: на mobile он выключен (открывает клавиатуру без действия). Вернуть на mobile — `layoutPresets={{ mobile: { autoFocus: true } }}`.
lengthFieldLengthnoСчётчик длины `current/max`
maxLengthnumbernoМаксимальное количество символов
namestringnoHTML name
onBlur((event: FocusEvent<HTMLTextAreaElement, Element>) => void)noКолбек блюра
onChange((value: string, event?: ChangeEvent<HTMLTextAreaElement>) => void)noКолбек смены значения
onCopyButtonClick(() => void)noКолбек после копирования
onFocus((event: FocusEvent<HTMLTextAreaElement, Element>) => void)noКолбек фокуса
readonlybooleannoТолько для чтения
resizablebooleanfalsenoМожно ли менять высоту мышкой за нижний угол. Игнорируется при `disabled` или `readonly`.
showClearButtonbooleantruenoКнопка очистки (видна при value && !readonly)
showHintIconbooleannoОтображение статус-иконки у подсказки (по умолчанию `true`)
validationState"default" | "error" | "success" | "warning"noСостояние валидации
valuestringnoЗначение (controlled-режим)

Types

FieldChatProps

Адаптивность

Раскладку компонент берёт из AdaptiveProvider (@cloud-ru/ds-adaptive) — отдельного пропа layoutType нет. На mobile прикреплённые файлы показываются над полем полноширинными карточками Attachment (на desktop — под полем, AttachmentSquare). Размер поля от раскладки не зависит.

autoFocus на mobile выключается (наследуется из @cloud-ru/ds-fields) — он открывает экранную клавиатуру без действия пользователя. Вернуть на mobile — через layoutPresets:

<FieldChat autoFocus layoutPresets={{ mobile: { autoFocus: true } }} />

Mobile включается автоматически при одном <AdaptiveProvider> в корне приложения (desktop-first).

Storybook

Figma