# Dialog Header

## Usage

`DialogHeader` gives a dialog a labelled title area and an optional close control. It reads context from the parent `Dialog`: the title becomes the dialog's accessible name, and focus lands on it when the dialog opens.

`title` is required. A subtitle is skipped when it is an empty string. The close button only appears when you pass `hasCloseButton`; clicking it emits `openChange(false)` and the parent decides whether to close.

```vue
<script setup lang="ts">
import { Dialog, DialogHeader } from '@astryx-vue/core/Dialog'
import { ref } from 'vue'

const isOpen = ref(false)
</script>

<template>
  <Dialog :is-open="isOpen" @open-change="isOpen = $event">
    <DialogHeader
      title="Edit profile"
      subtitle="Update your personal information"
      has-close-button
      @open-change="isOpen = $event"
    />
    <p>Dialog body content goes here.</p>
  </Dialog>
</template>
```

Without a parent `Dialog`, the title is not associated with any dialog and the close button does not take part in the dialog's default focus behaviour. Render it inside the default slot of `Dialog`.

### Anatomy

- **Header row**: Arranges the title block, optional start/end content, and close control.
- **Start content**: Wraps optional leading content.
- **Title block**: Groups the title and optional subtitle.
- **End content**: Groups optional trailing content with the optional close control.
- **Close icon**: Visual close glyph inside the close button.

## Examples

### Basic

A title, subtitle, and close button inside the default slot of Dialog. The close button renders only when hasCloseButton is passed.

```vue
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { Dialog, DialogHeader } from '@astryx-vue/core/Dialog'
import { ref } from 'vue'

const isOpen = ref(false)
</script>

<template>
  <div class="input-preview-grid">
    <Button label="Invite teammates" variant="secondary" @click="isOpen = true" />
    <Dialog :is-open="isOpen" width="420" @open-change="isOpen = $event">
      <DialogHeader
        title="Invite teammates"
        subtitle="Send invitations to join your workspace"
        has-close-button
        @open-change="isOpen = $event"
      />
      <p>Anyone you invite can view the workspace right away. You can change their access later.</p>
      <Button label="Send invites" variant="primary" @click="isOpen = false" />
    </Dialog>
  </div>
</template>
```

## Accessibility

The title is exposed as a heading through `role="heading"` and `aria-level="2"`, and it labels the parent dialog through `aria-labelledby`. A screen reader announces the dialog by its title text.

When the dialog opens, the title carries `tabindex="-1"` and receives initial focus, so keyboard users hear the name right away instead of starting in the middle of the body.

The close control is an `IconButton`. When `closeButtonLabel` is omitted, its accessible name follows the active language: Close in English, 关闭 in Chinese.

The `title` and `subtitle` slots take inline content, such as emphasis or a link. An empty subtitle string with no slot renders nothing.

Theme targets are `dialog-header`, `dialog-header-start-content`, `dialog-header-title-block`, `dialog-header-end-content`, and `dialog-header-close-icon`. They sit on the row, the leading slot, the title block, the trailing slot, and the close glyph. With a close button, the trailing slot pulls in on the block edges and the inline end, cancelling the button's own padding. `endContentEdgeCompensation` selects `inline`, `block`, or `all`.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | — | The dialog title. It receives default focus on open and names the dialog. Required. |
| `subtitle` | `string` | — | Secondary text under the title. An empty string with no `subtitle` slot renders nothing. |
| `hasCloseButton` | `boolean` | `false` | Shows the close button, which emits `openChange(false)` when clicked. |
| `endContentEdgeCompensation` | `'inline' \| 'block' \| 'all'` | `all` when a close button is shown | Which edges of the trailing slot are compensated. `inline` is the inline end, `block` is both block edges, `all` is both. Omitting it with no close button compensates nothing. |
| `closeButtonLabel` | `string` | Active language | Accessible name of the close button. Defaults to Close in English and 关闭 in Chinese. |
| `hasDivider` | `boolean` | `false` | Draws a themed rule along the bottom edge. The rule uses `--astryx-color-border`. |

## Events

- `openChange(isOpen: boolean)`: fires with `false` when the close button is clicked.

## Slots

- `title`: inline content in place of the title string. The heading still names the dialog.
- `subtitle`: inline content for the subtitle.
- `startContent`: content before the title, such as a back button.
- `endContent`: content before the close button.
