DynamicDialog
Базовые вызовы
Содержимое окна — обычный компонент с пропами и событиями. Диалог закрывается изнутри через useC3DynamicDialogContext().close(value).
Результаты
Нажмите кнопки выше — здесь появятся результаты вызовов.
Входные параметры
Компонент C3DynamicDialog не имеет пропов: он рендерит диалог, который открыли программно. Все параметры задаются в вызове open(Component, options) из useC3DynamicDialog().
Параметры open(Component, options)
| Имя | Тип | По умолчанию | Описание |
|---|---|---|---|
Component | Component | — | Обязательный первый аргумент: компонент, который будет отрисован внутри окна. |
options.title | string | '' | Заголовок. Попадает в aria-label. Пустая строка — шапка не рендерится. |
options.width | string | '32rem' | Ширина окна. Ограничена max-width: calc(100vw - var(--c3-margin-large)), поэтому длинные значения не ломают вёрстку. |
options.props | Record<string, unknown> | {} | Пропы компонента. |
options.on | Record<string, Function> | {} | Обработчики событий компонента: имя события → функция. |
options.closeOnBackdrop | boolean | true | Закрывать по клику по подложке. |
options.closeOnEscape | boolean | true | Закрывать по Escape. |
Методы useC3DynamicDialog()
| Имя | Возвращает | Описание |
|---|---|---|
open(Component, options?) | Promise<DynamicDialogResult> | Показать компонент в окне и дождаться закрытия. |
close(reason, result?) | — | Закрыть текущий диалог с указанием причины. Используется хостом. |
dismiss(result?) | — | Закрыть текущий диалог программно: причина 'programmatic'. |
reset() | — | Сбросить очередь: текущий и ожидающие диалоги резолвятся как закрытые программно. |
context | Ref<DynamicDialogState | null> | Показываемый диалог. |
isOpen() | boolean | Есть ли активные диалоги: показанный или ожидающие в очереди. |
useC3DynamicDialogContext() | DynamicDialogContext | undefined | Контекст текущего диалога. Вне окна возвращает undefined, а не бросает. |
Результат
Промис open() резолвится объектом DynamicDialogResult: { result?: unknown, reason: DynamicDialogCloseReason }. Причина закрытия — 'action' (значение передал сам диалог через контекст), 'escape', 'backdrop' или 'programmatic'.
Описание
DynamicDialog открывает произвольный компонент в модальном окне. Он нужен, когда содержимое диалога слишком специфично для повторного использования: форма редактирования одной сущности, отчёт, мастер настройки. Обычный C3Modal требует состояния v-model:open и слота с разметкой в вызывающем компоненте, а здесь достаточно одной строки:
const { open } = useC3DynamicDialog() и await open(EditDialog, { props }).
Отличие от MessageBox: там содержимое фиксировано (сообщение, иконка, кнопки), здесь содержимое — любой компонент со своими пропами и событиями. MessageBox подходит для подтверждений, DynamicDialog — для форм и мастеров.
Состояние общее для приложения, поэтому open() можно вызвать из composable, стора или обработчика. Вызовы не конфликтуют: если окно уже открыто, следующее встаёт в очередь и показывается после закрытия текущего.
Хост C3DynamicDialog нужно разместить один раз в корневом макете (например, в app.vue), а не на каждой странице.
Дополнительная информация
- Доступность: роль
dialog,aria-modal="true"; заголовок дублируется вaria-label. Рольalertdialogне используется — это уMessageBoxдля подтверждений. - Фокус при открытии переносится на первый фокусируемый элемент внутри компонента, при закрытии возвращается на элемент, открывший окно.
- Escape закрывает окно, Tab замыкает фокус внутри (фокус-тэп через
trapFocus). - Пока открыт диалог, прокрутка страницы блокируется (
lockBodyScroll). - Телепорт рендерится только на клиенте, поэтому SSR-разметка не расходится при нескольких таких компонентах.
- Анимация появления использует переход
c3-modal-*и отключается приprefers-reduced-motion. - Именованные слоты не поддерживаются: если содержимое требует слотов, заверните его в свой компонент и передайте в
open()уже его. - Компонент не делается глубоко реактивным (
shallowRef+markRaw), поэтому Vue не ругается на переданный компонент в консоли.
Пример использования
Диалог-форма, которая закрывается изнутри и сообщает результат вызывающему коду:
const EditDialog = defineComponent({ /* ... */ setup(props, { emit }) { const dialog = useC3DynamicDialogContext() return () => h('div', [/* поля */, h('button', { onClick: () => dialog?.close({ ok: true }) }, 'Готово')]) } })
const { open } = useC3DynamicDialog() const result = await open(EditDialog, { title: 'Профиль', props: { id: 42 } }) if (result.result) await save(result.result)