Files
basecoat/docs/_includes/components/dialog.njk
T

149 lines
3.7 KiB
Plaintext

{% macro dialog(
id,
trigger=None,
title=None,
description=None,
footer=None,
main_attrs={},
trigger_attrs={},
content_attrs={},
content_header_attrs={},
content_body_attrs={},
content_footer_attrs={},
open=false,
close_button=true,
close_on_overlay_click=true
) %}
{% if registerComponent('dialog') %}
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('dialog', (initialOpen = false, initialCloseOnOverlayClick = true) => ({
id: null,
open: false,
closeOnOverlayClick: true,
init() {
this.id = this.$el.id;
this.open = initialOpen;
this.closeOnOverlayClick = initialCloseOnOverlayClick;
},
show() {
if (!this.open) {
this.open = true;
this.$nextTick(() => {
this.$el.dispatchEvent(new CustomEvent('dialog:opened', { bubbles: true }));
setTimeout(() => this.$refs.dialog.focus(), 50);
});
}
},
hide() {
if (this.open) {
this.open = false;
this.$el.dispatchEvent(new CustomEvent('dialog:closed', { bubbles: true }));
}
},
handleControl(event) {
const detail = event.detail;
if (detail && detail.targetId === this.id) {
const action = detail.action || 'toggle';
if (action === 'open') this.show();
else if (action === 'close') this.hide();
}
},
$main: {
'@dialog:control.window'(e) { this.handleControl(e) },
},
$trigger: {
'@click'() { this.show() },
':aria-expanded'() { return this.open }
},
$content: {
'@keydown.escape'() { this.open && this.hide() },
':inert'() { return !this.open },
'@click'(e) { e.target === this.$el && this.closeOnOverlayClick && this.hide() },
'x-cloak': ''
}
}));
});
</script>
{% endif %}
<div
id="{{ id }}"
x-data="dialog({{ 'true' if open else 'false' }}, {{ 'true' if close_on_overlay_click else 'false' }})"
x-bind="$main"
class="dialog"
{% for key, value in main_attrs %}
{{ key }}="{{ value }}"
{% endfor %}
>
{% if trigger %}
<button
{% if id %}aria-controls="{{ id }}-dialog"{% endif %}
aria-expanded="false"
aria-controls="{{ id }}-dialog"
x-bind="$trigger"
{% for key, value in trigger_attrs %}
{{ key }}="{{ value }}"
{% endfor %}
>
{{ trigger }}
</button>
{% endif %}
<div
role="dialog"
id="{{ id }}-dialog"
x-ref="dialog"
tabindex="-1"
aria-modal="true"
aria-labelledby="{{ id }}-title"
inert
x-bind="$content"
>
<article
{% for key, value in content_attrs %}
{{ key }}="{{ value }}"
{% endfor %}
>
{% if title or description %}
<header
{% for key, value in content_header_attrs %}
{{ key }}="{{ value }}"
{% endfor %}
>
<h2 id="{{ id }}-title">{{ title | safe }}</h2>
<p>{{ description | safe }}</p>
</header>
{% endif %}
{% if caller %}
<section
{% for key, value in content_body_attrs %}
{{ key }}="{{ value }}"
{% endfor %}
>
{% if caller %}{{ caller() }}{% endif %}
</section>
{% endif %}
{% if footer %}
<footer
{% for key, value in content_footer_attrs %}
{{ key }}="{{ value }}"
{% endfor %}
>
{{ footer | safe }}
</footer>
{% endif %}
{% if close_button %}
<button
@click="hide()"
aria-label="Close dialog"
>
{% lucide "x" %}
</button>
{% endif %}
</article>
</div>
</div>
{% endmacro %}