adattato html, test htmx con componente svelte

This commit is contained in:
fabio
2026-02-22 20:23:21 +01:00
parent 0cd6ce05cd
commit 83e85bf899
24 changed files with 3705 additions and 1491 deletions

1064
ui-kit/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,21 +4,24 @@
import { onMount } from 'svelte';
export let title = '';
export let open = false;
let rootEl: HTMLElement;
let panelEl: HTMLElement;
let hostEl: HTMLElement;
function isOpen(): boolean {
return !!hostEl?.hasAttribute('open');
}
function closeModal() {
open = false;
rootEl?.removeAttribute('open');
rootEl?.dispatchEvent(
hostEl?.removeAttribute('open');
hostEl?.dispatchEvent(
new CustomEvent('ui:close', { bubbles: true, composed: true })
);
}
function onKeyDown(event: KeyboardEvent) {
if (!open) return;
if (!isOpen()) return;
if (event.key === 'Escape') {
event.preventDefault();
@@ -64,10 +67,10 @@
}
onMount(() => {
const host = (rootEl.getRootNode() as ShadowRoot).host as HTMLElement;
hostEl = (rootEl.getRootNode() as ShadowRoot).host as HTMLElement;
const observer = new MutationObserver(() => {
open = host.hasAttribute('open');
if (open) {
if (isOpen()) {
setTimeout(() => {
const autofocus = panelEl?.querySelector<HTMLElement>('[autofocus]');
(autofocus || panelEl)?.focus();
@@ -75,37 +78,48 @@
}
});
observer.observe(host, { attributes: true, attributeFilter: ['open'] });
observer.observe(hostEl, { attributes: true, attributeFilter: ['open'] });
if (isOpen()) {
setTimeout(() => {
(panelEl as HTMLElement | undefined)?.focus();
}, 0);
}
return () => observer.disconnect();
});
</script>
{#if open}
<div class="overlay" on:click={onBackdropClick} on:keydown={onKeyDown} role="presentation">
<div class="panel" role="dialog" aria-modal="true" tabindex="-1" bind:this={panelEl}>
<header class="header">
<h3>{title}</h3>
<button type="button" class="close" on:click={closeModal} aria-label="Close">×</button>
</header>
<section class="body">
<slot />
</section>
</div>
<div class="overlay" on:click={onBackdropClick} on:keydown={onKeyDown} role="presentation" bind:this={rootEl}>
<div class="panel" role="dialog" aria-modal="true" tabindex="-1" bind:this={panelEl}>
<header class="header">
<h3>{title}</h3>
<button type="button" class="close" on:click={closeModal} aria-label="Close">×</button>
</header>
<section class="body">
<slot />
</section>
</div>
{/if}
<div bind:this={rootEl} hidden></div>
</div>
<style>
:host {
display: block;
}
.overlay {
position: fixed;
inset: 0;
background: var(--ui-overlay);
display: grid;
display: none;
place-items: center;
z-index: 1000;
}
:host([open]) .overlay {
display: grid;
}
.panel {
width: min(640px, calc(100vw - 32px));
max-height: calc(100vh - 48px);