Drawer.svelte 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <script lang="ts">
  2. import { onDestroy, onMount, createEventDispatcher } from 'svelte';
  3. import { flyAndScale } from '$lib/utils/transitions';
  4. import { fade, fly, slide } from 'svelte/transition';
  5. const dispatch = createEventDispatcher();
  6. export let show = false;
  7. export let className = '';
  8. let modalElement = null;
  9. let mounted = false;
  10. const handleKeyDown = (event: KeyboardEvent) => {
  11. if (event.key === 'Escape' && isTopModal()) {
  12. console.log('Escape');
  13. show = false;
  14. }
  15. };
  16. const isTopModal = () => {
  17. const modals = document.getElementsByClassName('modal');
  18. return modals.length && modals[modals.length - 1] === modalElement;
  19. };
  20. onMount(() => {
  21. mounted = true;
  22. });
  23. $: if (show && modalElement) {
  24. document.body.appendChild(modalElement);
  25. window.addEventListener('keydown', handleKeyDown);
  26. document.body.style.overflow = 'hidden';
  27. } else if (modalElement) {
  28. dispatch('close');
  29. window.removeEventListener('keydown', handleKeyDown);
  30. if (document.body.contains(modalElement)) {
  31. document.body.removeChild(modalElement);
  32. document.body.style.overflow = 'unset';
  33. }
  34. }
  35. onDestroy(() => {
  36. show = false;
  37. if (modalElement) {
  38. if (document.body.contains(modalElement)) {
  39. document.body.removeChild(modalElement);
  40. document.body.style.overflow = 'unset';
  41. }
  42. }
  43. });
  44. </script>
  45. <!-- svelte-ignore a11y-click-events-have-key-events -->
  46. <!-- svelte-ignore a11y-no-static-element-interactions -->
  47. <div
  48. bind:this={modalElement}
  49. class="modal fixed right-0 left-0 bottom-0 bg-black/60 w-full h-screen max-h-[100dvh] flex justify-center z-[999] overflow-hidden overscroll-contain"
  50. in:fly={{ y: 100, duration: 100 }}
  51. on:mousedown={() => {
  52. show = false;
  53. }}
  54. >
  55. <div
  56. class=" mt-auto max-w-full w-full bg-gray-50 dark:bg-gray-900 dark:text-gray-100 {className} max-h-[100dvh] overflow-y-auto scrollbar-hidden"
  57. on:mousedown={(e) => {
  58. e.stopPropagation();
  59. }}
  60. >
  61. <slot />
  62. </div>
  63. </div>
  64. <style>
  65. .modal-content {
  66. animation: scaleUp 0.1s ease-out forwards;
  67. }
  68. @keyframes scaleUp {
  69. from {
  70. transform: scale(0.985);
  71. opacity: 0;
  72. }
  73. to {
  74. transform: scale(1);
  75. opacity: 1;
  76. }
  77. }
  78. </style>