Files
Kotyata/layers/ui/components/notification/notification.vue
2026-03-17 13:24:22 +03:00

114 lines
2.1 KiB
Vue

<template>
<Transition
:name="cn.b()"
@before-leave="$emit('close')"
@after-leave="$emit('destroy')"
>
<UiAlert
v-show="visible"
:id="id"
:class="[cn.b(), verticalSide, horizontalSide]"
:title="title"
:type="type"
@mouseenter="clearTimer"
@mouseleave="startTimer"
>
<slot />
</UiAlert>
</Transition>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import useClassname from '../../composables/use-classname'
import UiAlert from '../alert/index.vue'
import type { NotificationPlacement, NotificationType } from './types'
export interface Props {
duration?: number
id?: string | number
offset?: number
placement?: NotificationPlacement
type?: NotificationType
title?: string
zIndex?: number
}
defineOptions({
name: 'UiNotification',
})
const props = withDefaults(defineProps<Props>(), {
type: 'neutral',
duration: 5000,
offset: 0,
placement: 'top-right',
zIndex: 0,
})
defineEmits(['close', 'destroy'])
const cn = useClassname('ui-notification')
const timerId = ref()
const visible = ref(false)
const verticalSide = computed(() => props.placement.split('-')[0])
const horizontalSide = computed(() => props.placement.split('-')[1])
function close() {
visible.value = false
}
function startTimer() {
if (props.duration > 0) {
timerId.value = setTimeout(() => {
if (visible.value)
close()
}, props.duration)
}
}
function clearTimer() {
if (timerId.value)
clearTimeout(timerId.value)
}
onMounted(() => {
startTimer()
visible.value = true
})
defineExpose({
visible,
close,
})
</script>
<style lang="scss">
.ui-notification {
position: fixed;
transition-duration: 0.2s;
transition-property: opacity, transform, left, right, top, bottom;
z-index: calc(8000 + v-bind('zIndex'));
width: 400px;
transform-origin: right top;
&.top {
top: v-bind('`${offset}px`');
}
&.bottom {
bottom: v-bind('`${offset}px`');
}
&.left {
left: 56px;
}
&.right {
right: 56px;
}
}
</style>