mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-12 13:18:22 +00:00
125 lines
3.6 KiB
Plaintext
125 lines
3.6 KiB
Plaintext
{% macro tabs(
|
|
id,
|
|
tabsets=[],
|
|
main_attrs=None,
|
|
tablist_attrs=None,
|
|
default_tab_index=1
|
|
)
|
|
%}
|
|
{% if registerComponent('tabs') %}
|
|
<script>
|
|
document.addEventListener('alpine:init', () => {
|
|
Alpine.data('tabs', (initialTabIndex = 0) => ({
|
|
activeTabIndex: initialTabIndex,
|
|
tabs: [],
|
|
panels: [],
|
|
|
|
init() {
|
|
this.$nextTick(() => {
|
|
this.tabs = Array.from(this.$el.querySelectorAll(':scope > [role=tablist] [role=tab]:not([disabled])'));
|
|
this.panels = Array.from(this.$el.querySelectorAll(':scope > [role=tabpanel]'));
|
|
if (this.tabs.length > 0) {
|
|
this.selectTab(this.tabs[initialTabIndex], false);
|
|
}
|
|
});
|
|
},
|
|
nextTab() {
|
|
if (this.tabs.length === 0) return;
|
|
let newIndex = (this.activeTabIndex + 1) % this.tabs.length;
|
|
this.selectTab(this.tabs[newIndex]);
|
|
},
|
|
prevTab() {
|
|
if (this.tabs.length === 0) return;
|
|
let newIndex = (this.activeTabIndex - 1 + this.tabs.length) % this.tabs.length;
|
|
this.selectTab(this.tabs[newIndex]);
|
|
},
|
|
selectTab(tab, focus = true) {
|
|
if (!tab || this.tabs.length === 0) return;
|
|
|
|
this.tabs.forEach((t, index) => {
|
|
const isSelected = t === tab;
|
|
t.setAttribute('aria-selected', isSelected);
|
|
t.setAttribute('tabindex', isSelected ? '0' : '-1');
|
|
if (isSelected) {
|
|
this.activeTabIndex = index;
|
|
this.activeTab = t;
|
|
if (focus) {
|
|
t.focus();
|
|
}
|
|
}
|
|
});
|
|
|
|
const panelId = tab.getAttribute('aria-controls');
|
|
if (!panelId) return;
|
|
|
|
this.panels.forEach(panel => {
|
|
panel.hidden = (panel.getAttribute('id') !== panelId);
|
|
});
|
|
},
|
|
|
|
$tablist: {
|
|
['@click'](event) {
|
|
const clickedTab = event.target.closest('[role=tab]');
|
|
if (clickedTab) {
|
|
this.selectTab(clickedTab);
|
|
}
|
|
},
|
|
['@keydown.arrow-right.prevent']() { this.nextTab() },
|
|
['@keydown.arrow-left.prevent']() { this.prevTab() },
|
|
},
|
|
}));
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
|
|
<div
|
|
class="tabs {{ main_attrs.class }}"
|
|
x-data="tabs({{ default_tab_index - 1 }})"
|
|
{% if id %}id="{{ id }}"{% endif %}
|
|
{% for key, value in main_attrs %}
|
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
{% endfor %}
|
|
>
|
|
<div
|
|
role="tablist"
|
|
aria-orientation="horizontal"
|
|
x-bind="$tablist"
|
|
{% for key, value in tablist_attrs %}
|
|
{{ key }}="{{ value }}"
|
|
{% endfor %}
|
|
>
|
|
{% for tabset in tabsets %}
|
|
<button
|
|
role="tab"
|
|
id="{{ tabset.id }}-tab-{{ loop.index }}"
|
|
aria-controls="{{ tabset.id }}-panel-{{ loop.index }}"
|
|
aria-selected="{{ 'true' if loop.index == default_tab_index else 'false' }}"
|
|
tabindex="0"
|
|
{% for key, value in tabset.tab_attrs %}
|
|
{{ key }}="{{ value }}"
|
|
{% endfor %}
|
|
>
|
|
{{ tabset.tab | safe }}
|
|
</button>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{% for tabset in tabsets %}
|
|
{% if tabset.panel %}
|
|
<div
|
|
role="tabpanel"
|
|
id="{{ tabset.id }}-panel-{{ loop.index }}"
|
|
aria-labelledby="{{ tabset.id }}-tab-{{ loop.index }}"
|
|
tabindex="-1"
|
|
aria-selected="{{ 'true' if loop.index == default_tab_index else 'false' }}"
|
|
{% if loop.index != default_tab_index %}hidden{% endif %}
|
|
{% for key, value in tabset.panel_attrs %}
|
|
{{ key }}="{{ value }}"
|
|
{% endfor %}
|
|
>
|
|
{{ tabset.panel | safe }}
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</div>
|
|
{% endmacro %} |