laif-ds
Version:
Design System di Laif con componenti React basati su principi di Atomic Design
132 lines (107 loc) • 4.84 kB
Markdown
Chat composer with autosizing textarea, optional file attachments, voice input (record/transcribe), and intelligent Enter-to-send behavior with interruption prompts.
---
## Props
Extends native `<textarea>` props.
| Prop | Type | Default | Description |
| ------------------ | ---------------------------------------------- | ---------- | ----------- |
| `value` | `string` | **required** | Controlled text value. |
| `isGenerating` | `boolean` | `false` | If true, shows stop button and may display interrupt prompt. |
| `submitOnEnter` | `boolean` | `true` | Press Enter to submit (Shift+Enter for newline). |
| `stop` | `() => void` | `undefined`| Stop generation handler (used with `isGenerating`). |
| `enableInterrupt` | `boolean` | `true` | If true, pressing Enter while generating shows confirm to interrupt. |
| `transcribeAudio` | `(blob: Blob) => Promise<string>` | `undefined`| Optional audio-to-text function. |
| `allowAttachments` | `boolean` | `false` | Enable file attachments UI. |
| `files` | `File[] | null` | `null` | Current attached files (when `allowAttachments`). |
| `setFiles` | `React.Dispatch<React.SetStateAction<File[] | null>>` | `undefined`| Setter for attachments. |
---
## Behavior
- **Enter to submit**: If `submitOnEnter` and not `shiftKey`, calls `form.requestSubmit()`.
- **Interrupt flow**: If `isGenerating` and `stop` and `enableInterrupt`, pressing Enter shows a prompt to confirm stopping the generation and sending the new message.
- **Autosize**: Textarea grows up to a max height, then scrolls.
- **Attachments**: Drag & drop, paste files; long pasted text (> 500 chars) becomes a text file. Uses `FilePreview` to show chips.
- **Voice input**: If supported, toggles microphone recording; shows visualizer while recording and a "transcribing" overlay after.
- **Actions**: Right-aligned action buttons: attach, mic, send/stop.
---
```tsx
import * as React from "react";
import { MessageInput } from "laif-ds";
export function BasicComposer() {
const [value, setValue] = React.useState("");
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log("Messaggio inviato:", value);
setValue("");
};
return (
<form onSubmit={onSubmit} className="w-full max-w-2xl">
<MessageInput value={value} onChange={(e) => setValue(e.target.value)} isGenerating={false} />
</form>
);
}
```
```tsx
import * as React from "react";
import { MessageInput } from "laif-ds";
export function WithAttachments() {
const [value, setValue] = React.useState("");
const [files, setFiles] = React.useState<File[] | null>(null);
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log("Messaggio inviato:", value, files);
setValue("");
setFiles(null);
};
return (
<form onSubmit={onSubmit} className="w-full max-w-2xl">
<MessageInput
value={value}
onChange={(e) => setValue(e.target.value)}
isGenerating={false}
allowAttachments
files={files}
setFiles={setFiles}
placeholder="Scrivi un messaggio o trascina file qui..."
/>
</form>
);
}
```
```tsx
import * as React from "react";
import { MessageInput } from "laif-ds";
export function Generating() {
const [value, setValue] = React.useState("");
const [isGenerating, setIsGenerating] = React.useState(true);
const stop = () => setIsGenerating(false);
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (isGenerating) return;
console.log("Messaggio inviato:", value);
setValue("");
setIsGenerating(true);
setTimeout(() => setIsGenerating(false), 3000);
};
return (
<form onSubmit={onSubmit} className="w-full max-w-2xl">
<MessageInput
value={value}
onChange={(e) => setValue(e.target.value)}
isGenerating={isGenerating}
stop={stop}
placeholder="L'AI sta generando una risposta..."
/>
</form>
);
}
```
---
- **File preview**: Uses `FilePreview` for attachment chips.
- **Paste handling**: Long text paste becomes a `.txt` file when attachments are enabled.
- **A11y**: Textarea has aria-label; action buttons have aria-labels as well.