Newer
Older
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%"
@close.stop="close"
@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>
<slot name="header-extra" />
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
modelValue: undefined,
isModal: false,
},
)
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
}>()
const slots = useSlots()
const localIsOpen = ref(false)
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
}
},
})
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,
})
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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>