mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-12 13:18:22 +00:00
130 lines
3.2 KiB
Plaintext
130 lines
3.2 KiB
Plaintext
{% macro popover(
|
|
id=None,
|
|
trigger=None,
|
|
main_attrs=None,
|
|
trigger_attrs=None,
|
|
content_attrs=None
|
|
) %}
|
|
{% if registerComponent('popover') %}
|
|
<script>
|
|
document.addEventListener('alpine:init', () => {
|
|
Alpine.data('popover', () => ({
|
|
open: false,
|
|
focusedIndex: null,
|
|
menuItems: [],
|
|
|
|
init() {
|
|
this.$nextTick(() => {
|
|
this.menuItems = Array.from(this.$el.querySelectorAll('[role=menuitem]'));
|
|
});
|
|
},
|
|
|
|
handleTriggerClick() {
|
|
this.open = !this.open;
|
|
},
|
|
|
|
handleEscape() {
|
|
if (this.open) this.open = false;
|
|
},
|
|
|
|
focusNavItem() {
|
|
if (this.menuItems.length === 0) return;
|
|
if (this.focusedIndex >= this.menuItems.length) {
|
|
this.focusedIndex = this.menuItems.length - 1;
|
|
}
|
|
if (this.focusedIndex < 0) {
|
|
this.focusedIndex = 0;
|
|
}
|
|
this.menuItems[this.focusedIndex].focus();
|
|
},
|
|
|
|
nextNavItem() {
|
|
if (this.menuItems.length === 0) return;
|
|
if (this.focusedIndex === null) {
|
|
this.focusedIndex = 0;
|
|
} else {
|
|
this.focusedIndex++;
|
|
}
|
|
this.focusNavItem();
|
|
},
|
|
|
|
prevNavItem() {
|
|
if (this.menuItems.length === 0) return;
|
|
if (this.focusedIndex === null) {
|
|
this.focusedIndex = 0;
|
|
} else {
|
|
this.focusedIndex--;
|
|
}
|
|
this.focusNavItem();
|
|
},
|
|
|
|
handleNavItemClick(event) {
|
|
if (this.menuItems.length === 0) return;
|
|
const menuItem = event.target.closest('[role=menuitem]');
|
|
if (menuItem && !menuItem.disabled) {
|
|
menuItem.blur();
|
|
this.open = false;
|
|
}
|
|
},
|
|
|
|
$trigger: {
|
|
'@click'() { this.handleTriggerClick() },
|
|
'@keydown.down.prevent'() { this.open && this.nextNavItem() },
|
|
':aria-expanded'() { return this.open },
|
|
},
|
|
|
|
$content: {
|
|
'@click'(e) { this.handleNavItemClick(e) },
|
|
'@keydown.escape.window'() { this.handleEscape() },
|
|
'@keydown.down.prevent'() { this.nextNavItem() },
|
|
'@keydown.up.prevent'() { this.prevNavItem() },
|
|
'@keydown.home.prevent'() { this.focusNavItem(0) },
|
|
'@keydown.end.prevent'() { this.focusNavItem(this.menuItems.length - 1) },
|
|
':aria-hidden'() { return !this.open },
|
|
'x-cloak': ''
|
|
},
|
|
}));
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
|
|
<div
|
|
class="popover {% if main_attrs %}{{ main_attrs.pop('class', '') }}{% endif %}"
|
|
x-data="popover"
|
|
@click.away="open = false"
|
|
{% if id %}id="{{ id }}"{% endif %}
|
|
{% for key, value in main_attrs %}
|
|
{{ key }}="{{ value }}"
|
|
{% endfor %}
|
|
>
|
|
{% if trigger %}
|
|
<button
|
|
type="button"
|
|
aria-haspopup="menu"
|
|
aria-expanded="false"
|
|
x-bind="$trigger"
|
|
{% if id %}
|
|
id="{{ id }}-trigger"
|
|
aria-controls="{{ id }}-menu"
|
|
{% endif %}
|
|
{% for key, value in trigger_attrs %}
|
|
{{ key }}="{{ value }}"
|
|
{% endfor %}
|
|
>
|
|
{{ trigger | safe }}
|
|
</button>
|
|
{% endif %}
|
|
<div
|
|
data-popover
|
|
aria-hidden="true"
|
|
x-bind="$content"
|
|
{% if id %}id="{{ id }}-menu"{% endif %}
|
|
{% for key, value in content_attrs %}
|
|
{{ key }}="{{ value }}"
|
|
{% endfor %}
|
|
>
|
|
{{ caller() }}
|
|
</div>
|
|
</div>
|
|
{% endmacro %}
|