import {awaitUntil, define, vlElement} from '/node_modules/vl-ui-core/dist/vl-core.js';
import {VlTabsPane} from '/src/vl-tabs-pane.js';
import '/src/vl-tab.js';
import '/node_modules/@govflanders/vl-ui-tabs/dist/js/tabs.js';
/**
* VlTabs
* @class
* @classdesc Gebruik de vl-tabs navigatie om veel maar gerelateerde informatie in kleinere stukken te verdelen. Wanneer er met tabs gewerkt wordt,
* zal een deel van de informatie verborgen worden. Het is daardoor belangrijk om de gebruiker hier attent op te maken en duidelijk over te brengen
* welke informatie in een tab zichtbaar zal zijn. Op mobiele toestellen zal de tab navigatie gevisualiseerd worden via een dropdown menu.
*
* @extends HTMLElement
* @mixes vlElement
*
* @property {boolean} data-vl-alt - Attribuut om de alt variant van de tabs te tonen. Deze variant dient gebruikt te worden als subnavigatie onder
* de functional header.
* @property {boolean} data-vl-responsive-label - Attribuut om de waarde in de tabs in responsive mode te veranderen. Enkel van toepassing wanneer
* geen tab is gekozen.
*
* @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-tabs/releases/latest|Release notes}
* @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-tabs/issues|Issues}
* @see {@link https://webcomponenten.omgeving.vlaanderen.be/demo/vl-tabs.html|Demo}
*
*/
export class VlTabs extends vlElement(HTMLElement) {
static get is() {
return 'vl-tabs';
}
static get _observedAttributes() {
return ['alt', 'responsive-label', 'active-tab', 'href'];
}
constructor() {
super(`
<style>
@import '/src/style.css';
</style>
<div id="tabs" data-vl-tabs data-vl-tabs-responsive-label="Navigatie">
<div id="tabs-wrapper" class="vl-tabs__wrapper">
<ul id="tab-list" class="vl-tabs" data-vl-tabs-list role="tablist"></ul>
<button type="button" data-vl-tabs-toggle aria-expanded="false" class="vl-tabs__toggle" data-vl-close="false">
<span id="data-vl-tabs-responsive-label">Navigatie</span>
</button>
</div>
</div>`);
}
connectedCallback() {
this._renderTabs();
this._renderSections();
this.__dress();
this._observer = this.__observeTabPanes((mutations) => this.__processTabPane(mutations));
}
disconnectedCallback() {
this._observer.disconnect();
}
get _dressed() {
return this.hasAttribute(VlTabs._dressedAttributeName);
}
static get _dressedAttributeName() {
return 'data-vl-tabs-dressed';
}
async __dress(forced) {
if (!this._dressed || forced) {
await customElements.whenDefined('vl-tab');
await customElements.whenDefined('vl-tab-section');
vl.tabs.dress(this.shadowRoot);
this.setAttribute(VlTabs._dressedAttributeName, '');
}
}
/**
* Wacht tot de tab initialisatie klaar is.
*
* @return {Promise}
*/
async ready() {
return awaitUntil(() => this._dressed);
}
get __tabs() {
return this.shadowRoot.getElementById('tabs');
}
get __tabList() {
return this.shadowRoot.getElementById('tab-list');
}
get __responsiveLabel() {
return this.shadowRoot.getElementById('data-vl-tabs-responsive-label');
}
get __tabPanes() {
return [...this.querySelectorAll(VlTabsPane.is)];
}
__getTabTemplate({id, title}) {
return this._template(`
<li is="vl-tab" data-vl-href="${this.__href}#${id}" data-vl-id="${id}">
<slot name="${id}-title-slot">${title}</slot>
</li>
`);
}
__getTabSectionTemplate({id}) {
return this._template(`
<section id="${id}-pane" is="vl-tab-section">
<slot name="${id}-slot"></slot>
</section>
`);
};
_addTab({tabPane, index}) {
const {id, title} = tabPane;
const element = this.__getTabTemplate({id, title});
if (index && index >= 0) {
this.__tabList.insertBefore(element, this.__tabList.children[index]);
} else {
this.__tabList.appendChild(element);
}
}
_removeTab(id) {
const element = this.__tabList.querySelector(`[data-vl-id="${id}"]`);
if (element) {
this.__tabList.removeChild(element);
}
}
_addTabSection({id, index}) {
this.__tabPanes[index].setAttribute('slot', `${id}-slot`);
const element = this.__getTabSectionTemplate({id});
if (index && index >= 0) {
this.__tabs.insertBefore(element, this.__tabs.children[++index]);
} else {
this.__tabs.appendChild(element);
}
}
_removeTabSection(id) {
const element = this.__tabs.querySelector(`#${id}-pane`);
if (element) {
this.__tabs.removeChild(element);
}
}
_renderTabs() {
this.__tabList.innerHTML = '';
this.__tabPanes.forEach((tabPane) => {
this._addTab({tabPane: tabPane});
});
}
_renderSections() {
this.__tabPanes.forEach((tabPane, index) => this._addTabSection({id: tabPane.id, index: index}));
}
_altChangedCallback(oldValue, newValue) {
if (newValue != undefined) {
this.__tabList.classList.add('vl-tabs--alt');
} else {
this.__tabList.classList.remove('vl-tabs--alt');
}
}
_responsiveLabelChangedCallback(oldValue, newValue) {
const value = newValue || 'Navigatie';
this.__tabs.setAttribute('data-vl-tabs-responsive-label', value);
this.__responsiveLabel.innerHTML = value;
}
async _activeTabChangedCallback(oldValue, newValue) {
await this.ready();
const tab = [...this.__tabList.children].find((tab) => tab.id == newValue);
if (tab && !tab.isActive) {
tab.activate();
}
}
_hrefChangedCallback(oldValue, newValue) {
this.__updateHrefs();
}
get __href() {
return this.getAttribute('data-vl-href') || window.location.pathname + window.location.search;
}
__updateHrefs() {
[...this.__tabList.children].forEach((tab) =>
tab.setAttribute('data-vl-href', `${this.__href}#${tab.id}`));
}
__observeTabPanes(callback) {
const observer = new MutationObserver(callback);
observer.observe(this, {childList: true});
return observer;
}
__processTabPane(mutations) {
const tabPanesToAdd = mutations.flatMap((mutation) => [...mutation.addedNodes]).filter((node) => node instanceof VlTabsPane);
tabPanesToAdd.forEach((tabPane) => this.__addTabAndSection(tabPane));
const tabPanesToDelete = mutations.flatMap((mutation) => [...mutation.removedNodes]).filter((node) => node instanceof VlTabsPane);
tabPanesToDelete.forEach((tabPane) => this.__removeTabAndSection(tabPane));
this.__dress();
}
__addTabAndSection(tabPane) {
const index = this.__tabPanes.indexOf(tabPane);
this._addTab({tabPane: tabPane, index: index});
this._addTabSection({id: tabPane.id, index: index});
}
__removeTabAndSection(tabPane) {
this._removeTab(tabPane.id);
this._removeTabSection(tabPane.id);
}
}
awaitUntil(() => window.vl && window.vl.tabs).then(() => define(VlTabs.is, VlTabs));