# Composer

Configurable prompt composer for chat, AI, and message surfaces.

This Angular implementation takes conceptual inspiration from Flux Composer, but the API, styling, and composition model follow the shadcn-style patterns already established in this library.

## Import

```ts
import {
  ComposerActionsLeadingComponent,
  ComposerActionsTrailingComponent,
  ComposerComponent,
  ComposerFooterComponent,
  ComposerHeaderComponent,
  ComposerInputComponent,
  ComposerTextareaComponent,
} from '@edsis/component/composer';
```

## Composition

```text
Composer
├── ComposerHeader (optional)
├── ComposerActionsLeading (optional)
├── textarea[ComposerInput] or ComposerInput
├── ComposerActionsTrailing (optional)
└── ComposerFooter (optional)
```

Use `textarea[ComposerInput]` when you want native textarea behavior, template-driven forms, or reactive forms.
Use `ComposerInput` when you want to project a custom rich-text surface or editor shell.

## Basic Usage

```html
<form (ngSubmit)="send()">
  <Composer (submitRequested)="send()">
    <textarea
      ComposerInput
      rows="2"
      maxRows="6"
      placeholder="How can I help you today?"
      [(ngModel)]="prompt"
      name="prompt"
    ></textarea>

    <ComposerActionsTrailing>
      <button Button type="submit" size="icon-sm" aria-label="Send prompt">Send</button>
    </ComposerActionsTrailing>
  </Composer>
</form>
```

## With Header

Use the header slot for file previews, avatars, upload summaries, or compact context cards.

```html
<Composer>
  <ComposerHeader>
    <div class="flex items-center gap-3 rounded-lg border border-border bg-muted/40 px-3 py-2">
      <img src="/avatar.png" alt="Uploaded file owner" class="size-10 rounded-md object-cover" />
      <div class="min-w-0">
        <p class="truncate text-sm font-medium">profile-shot.png</p>
        <p class="text-xs text-muted-foreground">2.1 MB</p>
      </div>
    </div>
  </ComposerHeader>

  <textarea ComposerInput rows="2" maxRows="6" placeholder="Ask about this asset..."></textarea>

  <ComposerActionsTrailing>
    <button Button type="button" size="sm">Send</button>
  </ComposerActionsTrailing>
</Composer>
```

## Inline Layout

Set `inline` when actions and input should share a compact single-row shell.

```html
<Composer inline submit="enter">
  <ComposerActionsLeading>
    <button Button type="button" variant="ghost" size="icon-sm" aria-label="Add attachment">
      +
    </button>
  </ComposerActionsLeading>

  <textarea ComposerInput rows="1" maxRows="4" placeholder="Reply..."></textarea>

  <ComposerActionsTrailing>
    <button Button type="button" variant="secondary" size="icon-sm" aria-label="Voice input">
      Mic
    </button>
    <button Button type="submit" size="icon-sm" aria-label="Send reply">Send</button>
  </ComposerActionsTrailing>
</Composer>
```

## Input Variant

Set `variant="input"` when the composer should align more closely with the radius and density of other input surfaces.

```html
<Composer variant="input">
  <textarea ComposerInput rows="2" maxRows="5" placeholder="What's on your mind?"></textarea>
</Composer>
```

## Height And Autosize

`rows` sets the initial height of the native textarea surface.
`maxRows` caps autosize growth before the textarea begins scrolling.

```html
<Composer>
  <textarea ComposerInput rows="3" maxRows="8" placeholder="Write a longer prompt..."></textarea>
</Composer>
```

## Submit Behavior

By default, keyboard submission uses `cmd-enter`, which means `Cmd+Enter` on macOS and `Ctrl+Enter` on Windows/Linux.

Use `submit="enter"` when pressing `Enter` should submit immediately. `Shift+Enter` still inserts a new line.

```html
<Composer submit="enter" (submitRequested)="send()">
  <textarea ComposerInput rows="1" maxRows="4" placeholder="Quick reply..."></textarea>
</Composer>
```

When `submitForm` stays `true`, the composer also calls the nearest native `form.requestSubmit()` after emitting `submitRequested`.

## Rich Text Slot

Project a custom editor shell through `ComposerInput` when you want a richer surface without changing the composer container API.

```html
<Composer>
  <ComposerInput>
    <div
      contenteditable="true"
      role="textbox"
      aria-multiline="true"
      class="min-h-20 w-full rounded-sm bg-transparent px-2 py-2 outline-none"
    >
      Draft a richer message...
    </div>
  </ComposerInput>

  <ComposerActionsLeading>
    <button Button type="button" variant="ghost" size="icon-sm" aria-label="Insert file">+</button>
  </ComposerActionsLeading>

  <ComposerActionsTrailing>
    <button Button type="button" size="icon-sm" aria-label="Send rich text message">Send</button>
  </ComposerActionsTrailing>
</Composer>
```

## Disabled And Invalid

Use the root inputs for shared composer state.

```html
<Composer [disabled]="isSending" [invalid]="promptInvalid">
  <textarea ComposerInput rows="2" maxRows="6"></textarea>
</Composer>
```

For native textarea integrations, `aria-invalid` can still be supplied directly on `textarea[ComposerInput]` when state comes from another layer.

## API Reference

### `ComposerComponent`

| Input        | Type                     | Default       | Notes                                                                 |
| ------------ | ------------------------ | ------------- | --------------------------------------------------------------------- |
| `variant`    | `'default' \| 'input'`   | `'default'`   | Controls shell radius and density.                                    |
| `inline`     | `boolean`                | `false`       | Places leading actions, input, and trailing actions in a compact row. |
| `disabled`   | `boolean`                | `false`       | Applies shared disabled treatment and prevents keyboard submit.       |
| `invalid`    | `boolean`                | `false`       | Applies destructive border and ring treatment.                        |
| `submit`     | `'cmd-enter' \| 'enter'` | `'cmd-enter'` | Controls keyboard submit behavior.                                    |
| `submitForm` | `boolean`                | `true`        | Requests native form submission after `submitRequested`.              |
| `class`      | `string`                 | `''`          | Appends classes to the composer host.                                 |

### `ComposerComponent` output

| Output            | Type            | Notes                                                                 |
| ----------------- | --------------- | --------------------------------------------------------------------- |
| `submitRequested` | `KeyboardEvent` | Emitted when keyboard submission is triggered from the input surface. |

### `ComposerTextareaComponent`

| Input          | Type             | Default | Notes                                               |
| -------------- | ---------------- | ------- | --------------------------------------------------- |
| `rows`         | `number`         | `2`     | Initial line count.                                 |
| `maxRows`      | `number \| null` | `null`  | Maximum autosize line count before scrolling.       |
| `disabled`     | `boolean`        | `false` | Disables the textarea even if the root is enabled.  |
| `aria-invalid` | `boolean`        | `false` | Applies invalid styling on the textarea input slot. |
| `class`        | `string`         | `''`    | Appends classes to the textarea host.               |

### Slot Components

`ComposerHeaderComponent`, `ComposerFooterComponent`, `ComposerActionsLeadingComponent`, `ComposerActionsTrailingComponent`, and `ComposerInputComponent` each accept a single `class` input.

## Accessibility

- Pair `textarea[ComposerInput]` with an accessible label from surrounding copy, `aria-label`, or form-field composition.
- Give icon-only buttons inside action slots explicit `aria-label` values.
- Keep meaningful supporting text in `ComposerFooter` or nearby description content.
- Use `submit="enter"` carefully in multiline experiences so users still understand `Shift+Enter` for a new line.
- When projecting a custom editor through `ComposerInput`, provide `role="textbox"`, `aria-multiline="true"`, and clear keyboard handling in the editor surface itself.

## Keyboard Interactions

- `Cmd+Enter` or `Ctrl+Enter` submits by default.
- `Enter` submits when `submit="enter"`.
- `Shift+Enter` keeps inserting new lines in `submit="enter"` mode.
- Standard textarea editing, selection, clipboard, and IME behavior remain native when using `textarea[ComposerInput]`.

## Styling And Theming

The composer uses the shared `border-input`, `bg-background`, `ring-ring`, `text-foreground`, and `placeholder:text-muted-foreground` tokens.

Override layout and density by passing `class` to the root or individual slot components.
Keep the projected input surface transparent so the composer shell remains the visible boundary.

## Angular Notes

- `textarea[ComposerInput]` remains a native textarea surface and autosizes without replacing native browser editing behavior.
- `ComposerInput` is intentionally presentational. It is meant for custom editor projection, not as a built-in rich-text editor.
- The composer shell is presentational and does not import layout or theme services, which keeps the entrypoint compatible with the library's component-layer rules.

## Source Inspiration

This component borrows the high-level idea of a structured prompt composer from Flux Composer, but the Angular API, slot names, styling tokens, keyboard behavior contract, and examples are implemented specifically for this library's shadcn-style component system.
