Composer
Where a message is written: text, attachments, emoji and @mentions.
SourcePackage @kerf-js/veneer
Preview
tsx
import { state } from '@kerf-js/core'import { Composer, Stack, Text } from '@kerf-js/veneer'import type { ComposerFile, ComposerSend} from '@kerf-js/veneer'import type { Peer } from '@kerf-js/veneer'export function Attach() { const files = state<ComposerFile[]>([]) const sent = state('') const send = (m: ComposerSend) => { sent.value = m.text files.value = [] } return ( <Stack gap="related"> <Composer label="Message #deploys" placeholder="Message #deploys" mentions={PEERS} files={files.value} onAttach={() => (files.value = [ ...files.value, { id: `f${files.value.length}`, name: 'latency-graph.png', }, ]) } onRemoveFile={(file) => (files.value = files.value.filter( (f) => f !== file, )) } onEmoji={(insert) => insert('π')} onSend={send} /> <Text subtle> {sent.value ? `Sent: ${sent.value}` : 'Type @ to mention someone.'} </Text> </Stack> )}const PEOPLE = [ { id: 'mara', name: 'Mara Lindqvist', email: 'mara@kerf.dev', role: 'Owner', team: 'Platform', initials: 'ML', }, { id: 'jun', name: 'Jun Tanaka', email: 'jun@kerf.dev', role: 'Admin', team: 'Platform', initials: 'JT', }, { id: 'priya', name: 'Priya Raman', email: 'priya@kerf.dev', role: 'Member', team: 'Web', initials: 'PR', }, { id: 'tomas', name: 'TomΓ‘s Oliveira', email: 'tomas@kerf.dev', role: 'Member', team: 'Web', initials: 'TO', }, { id: 'lena', name: 'Lena Fischer', email: 'lena@kerf.dev', role: 'Member', team: 'Data', initials: 'LF', }, { id: 'noor', name: 'Noor Haddad', email: 'noor@kerf.dev', role: 'Viewer', team: 'Data', initials: 'NH', }, { id: 'sam', name: 'Sam Okafor', email: 'sam@kerf.dev', role: 'Member', team: 'Mobile', initials: 'SO', }, { id: 'ines', name: 'InΓ©s Vidal', email: 'ines@kerf.dev', role: 'Viewer', team: 'Mobile', initials: 'IV', },]const PEERS: Peer[] = PEOPLE.map((p, i) => ({ id: p.id, name: p.name, color: i + 1,}))Installation
npm install @kerf-js/veneerUsage
tsx
import { Composer } from '@kerf-js/veneer'Accessibility
- Enter
- Sends
- ShiftEnter
- Adds a line
- ββ
- Moves through suggestions
- Esc
- Closes the suggestions, then the quote
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | β | The textarea's name: "Message #calendar-engine". |
placeholder | string | β | Shown while empty. |
quote | State<QuoteDraftValue | null> | β | The quote being drafted, for a Thread to fill. |
mentions | Mentionable[] | β | People to suggest after @. |
files | ComposerFile[] | β | Attached files. |
compact | boolean | false | Hides the keyboard hint. |
input | ((el: HTMLTextAreaElement) => void) | β | Reaches the textarea, for focus. |
| Event | Type | Default | Description |
|---|---|---|---|
onSend | (m: ComposerSend) => void | β | Called with the text and any quote. |
onRemoveFile | ((f: ComposerFile) => void) | β | Removes one. |
onAttach | (() => void) | β | Shows the attach button. |
onEmoji | ((insert: (text: string) => void) => void) | β | The emoji slot: open a picker, then call insert with what was picked. |
onTyping | (() => void) | β | Called as people type. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="composer"] [data-part="sr-only"]
sr-only
RelatedThreadMentions input