You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/site/content/examples/15-composition/04-modal/Modal.svelte

82 lines
1.6 KiB

<script>
import { createEventDispatcher, onDestroy } from 'svelte';
const dispatch = createEventDispatcher();
const close = () => dispatch('close');
let modal;
const handle_keydown = e => {
if (e.key === 'Escape') {
close();
return;
}
if (e.key === 'Tab') {
// trap focus
const nodes = modal.querySelectorAll('*');
const tabbable = Array.from(nodes).filter(n => n.tabIndex >= 0);
let index = tabbable.indexOf(document.activeElement);
if (index === -1 && e.shiftKey) index = 0;
index += tabbable.length + (e.shiftKey ? -1 : 1);
index %= tabbable.length;
tabbable[index].focus();
e.preventDefault();
}
};
const previously_focused = typeof document !== 'undefined' && document.activeElement;
if (previously_focused) {
onDestroy(() => {
previously_focused.focus();
});
}
</script>
<svelte:window on:keydown={handle_keydown}/>
<div class="modal-background" on:click={close}></div>
<div class="modal" role="dialog" aria-modal="true" bind:this={modal}>
<slot name="header"></slot>
<hr>
<slot></slot>
<hr>
<!-- svelte-ignore a11y-autofocus -->
<button autofocus on:click={close}>close modal</button>
</div>
<style>
.modal-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.3);
}
.modal {
position: absolute;
left: 50%;
top: 50%;
width: calc(100vw - 4em);
max-width: 32em;
max-height: calc(100vh - 4em);
overflow: auto;
transform: translate(-50%,-50%);
padding: 1em;
border-radius: 0.2em;
background: white;
}
button {
display: block;
}
</style>