HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //home/arjun/projects/buyercall/node_modules/bootstrap-vue-next/src/components/BToast/BToast.vue
<template>
  <BTransition :no-fade="noFadeBoolean">
    <div
      v-if="isToastVisible"
      :id="id"
      ref="element"
      class="toast"
      :class="[toastClass, computedClasses]"
      tabindex="0"
      :role="!isToastVisible ? undefined : isStatusBoolean ? 'status' : 'alert'"
      :aria-live="!isToastVisible ? undefined : isStatusBoolean ? 'polite' : 'assertive'"
      :aria-atomic="!isToastVisible ? undefined : true"
    >
      <component :is="headerTag" v-if="$slots.title || title" class="toast-header">
        <slot name="title" :hide="hide">
          <strong class="me-auto">
            {{ title }}
          </strong>
        </slot>
        <BCloseButton v-if="!noCloseButtonBoolean" @click="hide" />
      </component>
      <template v-if="$slots.default || body">
        <component
          :is="computedTag"
          class="toast-body"
          style="display: block"
          :class="bodyClass"
          v-bind="computedLinkProps"
          @click="computedLink ? hide : () => {}"
        >
          <slot :hide="hide">
            {{ body }}
          </slot>
        </component>
      </template>
      <BProgress
        v-if="typeof modelValue === 'number' && progressProps !== undefined"
        :animated="progressProps.animated"
        :precision="progressProps.precision"
        :show-progress="progressProps.showProgress"
        :show-value="progressProps.showValue"
        :striped="progressProps.striped"
        :variant="progressProps.variant"
        :max="modelValue"
        :value="remainingMs"
        height="4px"
      />
    </div>
  </BTransition>
</template>

<script setup lang="ts">
import {computed, onBeforeUnmount, ref, toRef, watch, watchEffect} from 'vue'
import {
  useBLinkHelper,
  useBooleanish,
  useColorVariantClasses,
  useCountdown,
} from '../../composables'
import type {BToastProps} from '../../types'
import BTransition from '../BTransition/BTransition.vue'
import BCloseButton from '../BButton/BCloseButton.vue'
import BLink from '../BLink/BLink.vue'
import {useElementHover, useToNumber, useVModel} from '@vueuse/core'
import BProgress from '../BProgress/BProgress.vue'

// TODO scheduling issue -- when multiple are opened in quick succession, and closed in quick succession,
// Find index can get lost, leading to one or multiple staying orphaned
// TODO appendToast from BToaster

const props = withDefaults(defineProps<BToastProps>(), {
  animation: true,
  autoHide: true,
  bgVariant: null,
  body: undefined,
  bodyClass: undefined,
  delay: 5000,
  headerClass: undefined,
  headerTag: 'div',
  id: undefined,
  interval: 1000,
  isStatus: false,
  modelValue: false,
  noCloseButton: false,
  noFade: false,
  noHoverPause: false,
  progressProps: undefined,
  showOnPause: true,
  solid: false,
  textVariant: null,
  title: undefined,
  toastClass: undefined,
  // Link props
  // All others use defaults
  active: undefined,
  activeClass: undefined,
  append: undefined,
  disabled: undefined,
  exactActiveClass: undefined,
  href: undefined,
  icon: undefined,
  opacity: undefined,
  opacityHover: undefined,
  rel: undefined,
  replace: undefined,
  routerComponentName: undefined,
  target: undefined,
  to: undefined,
  underlineOffset: undefined,
  underlineOffsetHover: undefined,
  underlineOpacity: undefined,
  underlineOpacityHover: undefined,
  underlineVariant: undefined,
  variant: undefined,
  // End link props
})

const emit = defineEmits<{
  'close': []
  'close-countdown': [value: number]
  'closed': []
  'destroyed': []
  'update:modelValue': [value: boolean | number]
}>()

const element = ref<HTMLElement | null>(null)

const isHovering = useElementHover(element)
const modelValue = useVModel(props, 'modelValue', emit)

const {computedLink, computedLinkProps} = useBLinkHelper(props)

// TODO animation is never used
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const animationBoolean = useBooleanish(() => props.animation)
const isStatusBoolean = useBooleanish(() => props.isStatus)
// TODO autohide is never used
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const autoHideBoolean = useBooleanish(() => props.autoHide)
const noCloseButtonBoolean = useBooleanish(() => props.noCloseButton)
const noFadeBoolean = useBooleanish(() => props.noFade)
const noHoverPauseBoolean = useBooleanish(() => props.noHoverPause)
const showOnPauseBoolean = useBooleanish(() => props.showOnPause)
const intervalNumber = useToNumber(() => props.interval)
// TODO solid is never used
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const solidBoolean = useBooleanish(() => props.solid)
const resolvedBackgroundClasses = useColorVariantClasses(props)
const countdownLength = toRef(() => (typeof modelValue.value === 'boolean' ? 0 : modelValue.value))

const {
  isActive,
  pause,
  restart,
  resume,
  stop,
  isPaused,
  value: remainingMs,
} = useCountdown(countdownLength, intervalNumber, {
  immediate: typeof modelValue.value === 'number',
})

watchEffect(() => {
  emit('close-countdown', remainingMs.value)
})

const computedTag = toRef(() => (computedLink.value ? BLink : 'div'))

const isToastVisible = toRef(() =>
  typeof modelValue.value === 'boolean'
    ? modelValue.value
    : isActive.value || (showOnPauseBoolean.value && isPaused.value)
)

// Unlike the Alert counterpart, we actually want to emit to fully destroy our Toast (handled by the toaster)
watch(isActive, (newValue) => {
  if (newValue === false && isPaused.value === false) {
    emit('destroyed')
  }
})

const computedClasses = computed(() => [
  resolvedBackgroundClasses.value,
  {
    show: isToastVisible.value,
  },
])

const hide = () => {
  emit('close')

  if (typeof modelValue.value === 'boolean') {
    modelValue.value = false
  } else {
    modelValue.value = 0
    stop()
  }

  emit('closed')
}

const onMouseEnter = () => {
  if (noHoverPauseBoolean.value) return
  pause()
}

watch(isHovering, (newValue) => {
  if (newValue) {
    onMouseEnter()
    return
  }
  resume()
})

onBeforeUnmount(stop)

defineExpose({
  pause,
  restart,
  resume,
  stop,
})
</script>