Внешняя кнопка и журнал событий
Автоматическая кнопка отключена. Основная кнопка работает через Data API; соседняя вызывает VGRollup.toggle с тем же управляющим элементом. Журнал показывает callbacks и DOM-события.
Внешняя кнопка полезна, когда действия должны находиться в собственной панели. Здесь VGRollup не создаёт автоматическую кнопку: её разметка принадлежит приложению. Модуль обновляет её подпись и aria-expanded при каждом переключении.
Кнопка «Переключить через API» обращается к тому же контейнеру и передаёт основной управляющий элемент. Благодаря этому состояние остаётся согласованным, а журнал получает одинаковые callbacks и события независимо от способа переключения.
Прочитайте текущее состояние, сверните описание и сравните записи журнала. Сначала вызывается callback, затем контейнер отправляет DOM-событие show или hide. Для инициализации доступен отдельный callback, но не DOM-событие.
<div class="rollup-demo">
<div id="rollup-api" class="rollup-demo-copy">
<p>Внешняя кнопка полезна, когда действия должны находиться в собственной панели. Здесь VGRollup не создаёт автоматическую кнопку: её разметка принадлежит приложению. Модуль обновляет её подпись и aria-expanded при каждом переключении.</p>
<p>Кнопка «Переключить через API» обращается к тому же контейнеру и передаёт основной управляющий элемент. Благодаря этому состояние остаётся согласованным, а журнал получает одинаковые callbacks и события независимо от способа переключения.</p>
<p>Прочитайте текущее состояние, сверните описание и сравните записи журнала. Сначала вызывается callback, затем контейнер отправляет DOM-событие show или hide. Для инициализации доступен отдельный callback, но не DOM-событие.</p>
</div>
<div class="rollup-demo-actions">
<button id="rollup-api-toggle" type="button" class="btn btn-primary btn-sm"
data-vg-toggle="rollup" data-vg-target="#rollup-api"
aria-controls="rollup-api" aria-expanded="false">Развернуть заметку</button>
<button id="rollup-api-call" type="button" class="btn btn-surface btn-sm">Переключить через API</button>
<button id="rollup-api-read" type="button" class="btn btn-surface btn-sm">Прочитать состояние</button>
</div>
<output id="rollup-api-state" class="rollup-demo-result" aria-live="polite"></output>
<pre id="rollup-api-log" class="rollup-demo-result rollup-demo-log" aria-label="Журнал VGRollup" aria-live="polite"></pre>
</div>
/**
* Описание: внешнее управление VGRollup с журналом событий.
* Возможности: Data API, статический toggle, чтение isShow, callbacks и DOM-события.
*/
import { VGRollup } from 'vgapp';
function initRollupDemo() {
const root = document.querySelector('#rollup-api');
if (!root || VGRollup.getInstance(root)) return;
const control = document.querySelector('#rollup-api-toggle');
const state = document.querySelector('#rollup-api-state');
const log = document.querySelector('#rollup-api-log');
const entries = [];
const record = (message) => {
entries.unshift(message);
log.textContent = entries.slice(0, 12).join('\n');
};
const renderState = (instance) => {
state.textContent = instance.isShow() ? 'Состояние: развёрнуто' : 'Состояние: свёрнуто';
};
for (const name of ['show', 'hide']) {
root.addEventListener(`vg.rollup.${name}`, (event) => {
record(`DOM ${name}: relatedTarget=#${event.detail.relatedTarget.id}`);
renderState(VGRollup.getInstance(root));
});
}
VGRollup.init(root, {
height: 112,
fade: false,
button: { enabled: false, more: 'Развернуть заметку', less: 'Свернуть заметку' },
callbacks: {
init: () => record('callback init'),
expand: () => record('callback expand'),
collapse: () => record('callback collapse')
}
}, (instance) => {
record('init callback: экземпляр получен');
renderState(instance);
});
document.querySelector('#rollup-api-call').addEventListener('click', () => VGRollup.toggle(root, control));
document.querySelector('#rollup-api-read').addEventListener('click', () => {
const instance = VGRollup.getInstance(root);
record(`isShow(): ${instance.isShow()}`);
renderState(instance);
});
}
initRollupDemo();
/* Композиция примеров; обрезкой и видимостью управляет VGRollup. */
.rollup-demo { min-width: 0; }
.rollup-demo-copy { line-height: 28px; }
.rollup-demo-copy p { margin: 0 0 1rem; }
.rollup-demo-copy p:last-child { margin-bottom: 0; }
.rollup-demo-list { margin: 0; padding-left: 1.5rem; }
.rollup-demo-item { padding: .5rem 0; }
.rollup-demo-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.5rem; }
.rollup-demo-result {
display: block;
margin: 1.5rem 0 0;
padding: .75rem;
border: 1px solid var(--vg-border-default);
border-radius: .5rem;
background: var(--vg-background-secondary);
color: var(--vg-text-primary);
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.rollup-demo-log { max-height: 16rem; overflow-y: auto; }
.rollup-demo-empty { margin-top: 1.5rem; color: var(--vg-text-secondary); }