# useImperativeDialog

## 使用方法

不用自己管「开没开」这个状态，就能弹出对话框。调 `dialog.show(content, options)` 打开，调 `dialog.hide()` 关掉。把 `dialog.Host` 在模板里渲染一次即可。`content` 是个返回 VNode 的函数，所以写成 `() => h(内容组件)`。

```ts
import { useImperativeDialog } from '@astryx-vue/core/Dialog'
```

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

const dialog = useImperativeDialog({ width: 400 })
const DialogHost = dialog.Host

function askToDelete(): void {
  dialog.show(
    () => h(DialogHeader, { title: '删除项目？', hasCloseButton: true }),
    { purpose: 'form' },
  )
}
</script>

<template>
  <button type="button" @click="askToDelete">
    删除项目
  </button>
  <DialogHost />
</template>
```

## 示例

常见配置、变体和状态。

### Dialog — 确认

做不可逆的操作前，先让用户确认。删除项目、移除成员、吊销 API key 这类事都该这么做。

```vue
<script setup lang="ts">
import { Dialog, useImperativeDialog } from '@astryx-vue/core/Dialog'
import { h } from 'vue'
import ConfirmBody from './confirm-body.vue'

const dialog = useImperativeDialog({ width: 400, purpose: 'form' })

function openDialog() {
  dialog.show(() => h(ConfirmBody, { requestClose: () => dialog.hide() }))
}
</script>

<template>
  <Dialog is-open is-inline :width="400" purpose="form">
    <ConfirmBody :request-close="openDialog" />
  </Dialog>
  <component :is="dialog.Host" />
</template>
```

### Dialog — 表单

不离开当前页面就收集用户输入。purpose 用 form，点遮罩不会关掉。适合改个人资料、新建条目、就地改设置。

```vue
<script setup lang="ts">
import { Dialog, useImperativeDialog } from '@astryx-vue/core/Dialog'
import { h } from 'vue'
import FormBody from './form-body.vue'

const dialog = useImperativeDialog({ purpose: 'form', width: 480 })

function openDialog() {
  dialog.show(() => h(FormBody, { requestClose: () => dialog.hide() }))
}
</script>

<template>
  <Dialog is-open is-inline purpose="form" :width="480">
    <FormBody :request-close="openDialog" />
  </Dialog>
  <component :is="dialog.Host" />
</template>
```

### Dialog — 必须响应

Escape 和点遮罩都关不掉，用户必须明确选一个动作。purpose 用 required。适合转移所有权、法律确认，以及不能跳过的关键决定。

```vue
<script setup lang="ts">
import { Dialog, useImperativeDialog } from '@astryx-vue/core/Dialog'
import { h } from 'vue'
import RequiredBody from './required-body.vue'

const dialog = useImperativeDialog({ purpose: 'required' })

function openDialog() {
  dialog.show(() => h(RequiredBody, { requestClose: () => dialog.hide() }))
}
</script>

<template>
  <Dialog is-open is-inline purpose="required">
    <RequiredBody :request-close="openDialog" />
  </Dialog>
  <component :is="dialog.Host" />
</template>
```

### Dialog — 可滚动

限制对话框高度，内容超出时在框内滚动。适合条款、许可协议、更新日志，以及任何要用户读完再接受的长文。

```vue
<script setup lang="ts">
import { Dialog, useImperativeDialog } from '@astryx-vue/core/Dialog'
import { h } from 'vue'
import ScrollBody from './scroll-body.vue'

const dialog = useImperativeDialog({ maxHeight: '50dvh' })

function openDialog() {
  dialog.show(() => h(ScrollBody, { requestClose: () => dialog.hide() }))
}
</script>

<template>
  <Dialog is-open is-inline :max-height="360">
    <ScrollBody :request-close="openDialog" />
  </Dialog>
  <component :is="dialog.Host" />
</template>
```

## 参数

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `defaultOptions` | `ImperativeDialogOptions` | `{}` | 每次 `show()` 都带上的默认配置，就是 `Dialog` 的属性去掉 `isOpen`。某次调用自己再传一份，会覆盖在这些之上。 |

## 返回值

| 名称 | 类型 | 说明 |
| --- | --- | --- |
| `show` | `(content: () => VNodeChild, options?: ImperativeDialogOptions) => void` | 按给定内容打开对话框。配置就是 `Dialog` 的属性去掉 `isOpen` 和内容。 |
| `hide` | `() => void` | 关掉对话框。 |
| `isOpen` | `Readonly<Ref<boolean>>` | 对话框当前是否打开。 |
| `Host` | `Component` | 承载对话框的组件。在模板里渲染一次：`<component :is="dialog.Host" />`。 |

## 配置项

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `width` | `number \| string` | — | 期望宽度。数字按像素，字符串原样使用。全屏变体忽略它。 |
| `maxHeight` | `number \| string` | — | 最大高度。数字按像素，字符串原样使用。全屏变体忽略它。 |
| `position` | `DialogPosition` | 居中 | 固定位置。水平方向用 `start` 和 `end`，RTL 下自动镜像。 |
| `variant` | `'standard' \| 'fullscreen'` | `'standard'` | 标准对话框由 `width` 和 `maxHeight` 定尺寸；全屏的占满视口。 |
| `purpose` | `'info' \| 'form' \| 'required'` | `'info'` | 用什么方式关。required 禁用 Escape 和遮罩；form 保留 Escape、禁用遮罩；info 两者都允许。 |
| `padding` | `DialogPadding` | 主题默认值 | 内边距档位，对应 `--astryx-spacing-*` 这些 token。 |
