VGAlert

Подтверждения и сообщения: modal, dropdown, overlay, Data API и AJAX.

Способы отображения

Dropdown, overlay в модалке и боковой панели.

Под каждым примером — его HTML, JavaScript и CSS. Подключите JS из vgapp и SCSS из vgapp/scss (или готовый CSS пакета). Кнопки и раскладка используют OKAUX 1.0.2; тема сайта управляется OKAUX.

Компактный dropdown

Панель располагается рядом с relatedTarget. Клик вне панели или Esc отменяет действие; без опорного элемента используется modal.

Ожидает действия.

HTML
<button type="button" class="btn btn-primary btn-sm" id="alert-dropdown-trigger">Подтверждение рядом с кнопкой</button>
<p id="alert-dropdown-result" class="mt-3 mb-0" role="status">Ожидает действия.</p>
JavaScript
/**
 * Описание: рабочий пример VGAlert для копирования и демо.
 * Возможности: запуск публичного API и отображение результата без изменения данных.
 */
import { VGAlert } from 'vgapp';

function initAlertDemo() {
  const button = document.querySelector('#alert-dropdown-trigger');
  if (!button) return;
  const result = document.querySelector('#alert-dropdown-result');
  button.addEventListener('click', () => {
    VGAlert.call({
      ...{
        "size": "compact",
        "theme": "warning",
        "render": {
          "type": "dropdown"
        },
        "dropdown": {
          "placement": "bottom-start"
        },
        "message": {
          "title": "Продолжить?",
          "description": "Повторите пример или отмените действие."
        },
        "buttons": {
          "agree": {
            "text": "Продолжить",
            "class": [
              "btn-primary",
              "btn-sm"
            ]
          },
          "cancel": {
            "text": "Отмена",
            "class": [
              "btn-surface",
              "btn-sm"
            ]
          }
        }
      },
      relatedTarget: button,
    }, 'ru')
      .then(value => { result.textContent = 'Подтверждено: accepted = ' + value.accepted; })
      .catch(error => { result.textContent = 'Отменено: accepted = ' + error.accepted; });
  });
}

initAlertDemo();
CSS
/* Дополнительные стили не требуются. */

Overlay внутри VGModal

Сравните render.dismiss: false и true. После согласия родитель остаётся открытым или закрывается; после отмены сохраняется.

HTML
<button type="button" class="btn btn-info btn-sm" data-vg-toggle="modal" data-vg-target="#alert-overlay-modal">Открыть VGModal</button>
<!-- Host -->
<div class="vg-modal fade" id="alert-overlay-modal" tabindex="-1" aria-labelledby="alert-overlay-modal-title" aria-hidden="true"><div class="vg-modal-dialog vg-modal-dialog-centered"><div class="vg-modal-content"><div class="vg-modal-header"><h2 id="alert-overlay-modal-title">Редактирование проекта</h2><button type="button" class="vg-btn-close" data-vg-dismiss="modal" data-vg-target="#alert-overlay-modal" aria-label="Закрыть"></button></div>
<div class="vg-modal-body"><p>Подтверждение останется внутри текущего контейнера. Отмена сохраняет его открытым.</p><button type="button" class="btn btn-primary btn-sm" id="alert-overlay-modal-keep">Подтвердить и остаться</button>
<button type="button" class="btn btn-surface btn-sm" id="alert-overlay-modal-dismiss">Подтвердить и закрыть</button>
<p id="alert-overlay-modal-result" role="status" class="mt-3">Ожидает действия.</p></div></div></div></div>
JavaScript
/**
 * Описание: рабочий пример VGAlert для копирования и демо.
 * Возможности: запуск публичного API и отображение результата без изменения данных.
 */
import { VGAlert } from 'vgapp';

function initAlertDemo() {
  const host = document.querySelector('#alert-overlay-modal');
  if (!host) return;
  for (const action of ['keep', 'dismiss']) {
    const button = host.querySelector('#alert-overlay-modal-' + action);
    button.addEventListener('click', () => {
      VGAlert.call({
        relatedTarget: button,
        size: 'compact',
        theme: 'info',
        render: { type: 'overlay', dismiss: action === 'dismiss' },
        message: { title: 'Применить изменения?', description: 'Это демонстрация без сохранения данных.' },
        buttons: {"agree":{"text":"Продолжить","class":["btn-primary","btn-sm"]},"cancel":{"text":"Отмена","class":["btn-surface","btn-sm"]}},
      })
        .then(() => { host.querySelector('[role="status"]').textContent = 'Действие подтверждено.'; })
        .catch(() => { host.querySelector('[role="status"]').textContent = 'Отменено. Контейнер остаётся открыт.'; });
    });
  }
}

initAlertDemo();
CSS
/* Дополнительные стили не требуются. */

Overlay в длинной VGModal

Откройте модалку, прокрутите таблицу до конца и вызовите alert нижней кнопкой. Окно подтверждения остаётся в видимой области прокрученной модалки.

HTML
<button type="button" class="btn btn-info btn-sm" data-vg-toggle="modal" data-vg-target="#alert-overlay-modal-scroll">Открыть длинную VGModal</button>
<!-- Host -->
<div class="vg-modal fade" id="alert-overlay-modal-scroll" tabindex="-1" aria-labelledby="alert-overlay-modal-scroll-title" aria-hidden="true">
  <div class="vg-modal-dialog vg-modal-lg">
    <div class="vg-modal-content">
      <div class="vg-modal-header">
        <h2 class="vg-modal-title" id="alert-overlay-modal-scroll-title">Длинный список заявок</h2>
        <button type="button" class="vg-btn-close" data-vg-dismiss="modal" data-vg-target="#alert-overlay-modal-scroll" aria-label="Закрыть"></button>
      </div>
      <div class="vg-modal-body">
        <p>Прокрутите модалку до нижней кнопки. Overlay должен открыться в видимой области, а не у начала таблицы.</p>
        <table class="vg-table vg-table-hovered" data-vg-table>
          <thead><tr><th data-field="id">№</th><th data-field="request">Заявка</th><th data-field="status">Статус</th></tr></thead>
          <tbody>
            <tr><td>101</td><td>Обновить контактные данные</td><td>Готово</td></tr>
            <tr><td>102</td><td>Проверить договор</td><td>В работе</td></tr>
            <tr><td>103</td><td>Подготовить акт</td><td>Новая</td></tr>
            <tr><td>104</td><td>Согласовать доставку</td><td>Готово</td></tr>
            <tr><td>105</td><td>Добавить пользователя</td><td>В работе</td></tr>
            <tr><td>106</td><td>Исправить реквизиты</td><td>Новая</td></tr>
            <tr><td>107</td><td>Проверить оплату</td><td>Готово</td></tr>
            <tr><td>108</td><td>Подготовить отчёт</td><td>В работе</td></tr>
            <tr><td>109</td><td>Согласовать смету</td><td>Новая</td></tr>
            <tr><td>110</td><td>Закрыть обращение</td><td>Готово</td></tr>
            <tr><td>111</td><td>Назначить исполнителя</td><td>В работе</td></tr>
            <tr><td>112</td><td>Обновить приложение</td><td>Новая</td></tr>
            <tr><td>113</td><td>Подтвердить получение</td><td>Готово</td></tr>
            <tr><td>114</td><td>Проверить вложения</td><td>В работе</td></tr>
            <tr><td>115</td><td>Запросить оригиналы</td><td>Новая</td></tr>
            <tr><td>116</td><td>Сверить остатки</td><td>Готово</td></tr>
            <tr><td>117</td><td>Обновить комментарий</td><td>В работе</td></tr>
            <tr><td>118</td><td>Подготовить ответ</td><td>Новая</td></tr>
            <tr><td>119</td><td>Отправить уведомление</td><td>Готово</td></tr>
            <tr><td>120</td><td>Завершить проверку</td><td>В работе</td></tr>
          </tbody>
        </table>
        <div class="mt-5">
          <button type="button" class="btn btn-primary btn-sm" id="alert-overlay-modal-scroll-trigger">Подтвердить внизу списка</button>
          <p id="alert-overlay-modal-scroll-result" role="status" class="mt-3 mb-0">Ожидает действия.</p>
        </div>
      </div>
    </div>
  </div>
</div>
JavaScript
/**
 * Описание: стенд VGAlert overlay внутри длинной прокручиваемой VGModal.
 * Возможности: воспроизведение вызова из нижней части таблицы и вывод результата Promise.
 */
import { VGAlert } from 'vgapp';

function initAlertDemo() {
  const host = document.querySelector('#alert-overlay-modal-scroll');
  const button = host?.querySelector('#alert-overlay-modal-scroll-trigger');
  const result = host?.querySelector('[role="status"]');
  if (!button || !result) return;

  button.addEventListener('click', () => {
    VGAlert.call({
      relatedTarget: button,
      size: 'compact',
      theme: 'warning',
      render: { type: 'overlay', dismiss: false },
      message: {
        title: 'Подтвердить выбранные заявки?',
        description: 'Alert открыт из нижней части длинной модалки и должен оставаться видимым.',
      },
      buttons: {
        agree: { text: 'Подтвердить', class: ['btn-primary', 'btn-sm'] },
        cancel: { text: 'Отмена', class: ['btn-surface', 'btn-sm'] },
      },
    }, 'ru')
      .then(() => { result.textContent = 'Действие подтверждено.'; })
      .catch(() => { result.textContent = 'Действие отменено.'; });
  });
}

initAlertDemo();
CSS
/* Дополнительные стили не требуются. */

Overlay внутри VGSidebar

Тот же публичный контракт внутри боковой панели. relatedTarget должен находиться в контейнере; иначе будет открыт отдельный modal.

HTML
<button type="button" class="btn btn-info btn-sm" data-vg-toggle="sidebar" data-vg-target="#alert-overlay-sidebar">Открыть VGSidebar</button>
<!-- Host -->
<aside class="vg-sidebar right" id="alert-overlay-sidebar" tabindex="-1" aria-labelledby="alert-overlay-sidebar-title" aria-hidden="true"><div class="vg-sidebar-header"><h2 id="alert-overlay-sidebar-title">Редактирование проекта</h2><button type="button" class="vg-btn-close" data-vg-dismiss="sidebar" data-vg-target="#alert-overlay-sidebar" aria-label="Закрыть"></button></div>
<div class="vg-sidebar-body"><p>Подтверждение останется внутри текущего контейнера. Отмена сохраняет его открытым.</p><button type="button" class="btn btn-primary btn-sm" id="alert-overlay-sidebar-keep">Подтвердить и остаться</button>
<button type="button" class="btn btn-surface btn-sm" id="alert-overlay-sidebar-dismiss">Подтвердить и закрыть</button>
<p id="alert-overlay-sidebar-result" role="status" class="mt-3">Ожидает действия.</p></div></aside>
JavaScript
/**
 * Описание: рабочий пример VGAlert для копирования и демо.
 * Возможности: запуск публичного API и отображение результата без изменения данных.
 */
import { VGAlert } from 'vgapp';

function initAlertDemo() {
  const host = document.querySelector('#alert-overlay-sidebar');
  if (!host) return;
  for (const action of ['keep', 'dismiss']) {
    const button = host.querySelector('#alert-overlay-sidebar-' + action);
    button.addEventListener('click', () => {
      VGAlert.call({
        relatedTarget: button,
        size: 'compact',
        theme: 'info',
        render: { type: 'overlay', dismiss: action === 'dismiss' },
        message: { title: 'Применить изменения?', description: 'Это демонстрация без сохранения данных.' },
        buttons: {"agree":{"text":"Продолжить","class":["btn-primary","btn-sm"]},"cancel":{"text":"Отмена","class":["btn-surface","btn-sm"]}},
      })
        .then(() => { host.querySelector('[role="status"]').textContent = 'Действие подтверждено.'; })
        .catch(() => { host.querySelector('[role="status"]').textContent = 'Отменено. Контейнер остаётся открыт.'; });
    });
  }
}

initAlertDemo();
CSS
#alert-overlay-sidebar { --vg-sidebar-horizontal-width: min(480px, 100vw); }
#alert-overlay-sidebar h2 { font-size: 1.25rem; }
#alert-overlay-sidebar .vg-sidebar-body > .btn { margin-bottom: .5rem; }