Skip to content
Snippets Groups Projects
ADialog.vue 2.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • <template>
      <dialog
    
        ref="dialogEl"
    
        class="tw-shadow-xl tw-border tw-border-gray-200 tw-rounded tw-p-0 tw-bg-white tw-z-30 tw-flex tw-flex-col"
        style="max-width: 95%"
    
        @click="maybeCloseFromClickOutside"
    
        <header class="tw-flex tw-justify-between tw-p-4 flex-none tw-items-center">
    
            <slot name="header" :title-class="titleClass">
              <p :class="titleClass">{{ title }}</p>
            </slot>
    
          </div>
          <button
            type="button"
    
            class="btn btn-default tw-w-8 tw-h-8 tw-ml-auto tw-p-0 tw-justify-center tw-rounded-full"
    
            tabindex="-1"
            @click="close"
          >
            <icon-system-uicons-close class="tw-w-6 tw-h-6" />
          </button>
        </header>
        <div class="tw-flex-1 tw-p-4 tw-overflow-y-auto tw-shadow-inner">
          <slot />
        </div>
        <footer
          v-if="slots.footer"
          class="tw-flex-none tw-p-4 tw-border-0 tw-border-t tw-border-solid tw-border-gray-200"
        >
          <slot name="footer" />
        </footer>
      </dialog>
    </template>
    
    <script lang="ts" setup>
    
    import { computed, nextTick, ref, useSlots, watch } from 'vue'
    
    defineOptions({ compatConfig: { MODE: 3 } })
    
    const titleClass = 'tw-text-lg tw-font-semibold tw-select-none tw-m-0'
    
    const props = withDefaults(
      defineProps<{
    
        modelValue?: boolean | undefined
    
        isModal?: boolean
    
        isModal: false,
      },
    )
    const emit = defineEmits<{
      (e: 'update:modelValue', value: boolean): void
    }>()
    const slots = useSlots()
    
    const localIsOpen = ref(false)
    
    const dialogEl = ref<HTMLDialogElement>()
    
    const isOpen = computed({
      get() {
        return props.modelValue !== undefined ? props.modelValue : localIsOpen.value
      },
      set(value: boolean) {
        if (props.modelValue !== undefined) {
          emit('update:modelValue', value)
        } else {
          localIsOpen.value = value
        }
      },
    })
    
    
    function close() {
    
      isOpen.value = false
    }
    
    function open() {
      isOpen.value = true
    
    function maybeCloseFromClickOutside(event: MouseEvent | PointerEvent) {
      // @ts-expect-error TS EventTarget does not contain nodeName
      if (event.target?.nodeName === 'DIALOG') close()
    }
    
    
    defineExpose({
      close,
      open,
      hide: close,
      show: open,
    })
    
    
      async (isOpen) => {
        if (isOpen && !dialogEl.value) {
          await nextTick()
        }
    
        if (dialogEl.value) {
          if (isOpen) {
            if (props.isModal) {
              dialogEl.value.showModal()
            } else {
              dialogEl.value.show()
            }
          } else if (dialogEl.value.open) {
            dialogEl.value.close()
          }
        }
      },
      { immediate: true },
    )
    </script>
    
    <style lang="postcss" scoped>
    dialog::backdrop {
      background: rgba(0, 0, 0, 0.5);
      backdrop-filter: blur(3px);
    }
    </style>