kodadot/nft-gallery

View on GitHub
libs/ui/src/components/NeoDropdown/NeoDropdown.vue

Summary

Maintainability
Test Coverage
<script>
import { ODropdown } from '@oruga-ui/oruga-next'
import { useElementBounding } from '@vueuse/core'

export default {
  mixins: [ODropdown],
  props: {
    mobileModal: {
      type: Boolean,
      default: false,
    },
    noShadow: {
      type: Boolean,
      default: false,
    },
    closeMenuOnMove: {
      type: Boolean,
      default: false,
    },
    position: {
      type: String,
      validator: (value) => {
        return (
          [
            'top-right',
            'top-left',
            'bottom-left',
            'bottom-right',
            'bottom-auto',
          ].indexOf(value) > -1
        )
      },
    },
  },
  data() {
    return {
      autoPosition: '',
    }
  },
  computed: {
    rootClasses() {
      return [
        'neo-dropdown',
        this.computedClass('rootClass', 'o-drop'),
        {
          [this.computedClass('disabledClass', 'o-drop--disabled')]:
            this.disabled,
        },
        {
          [this.computedClass('expandedClass', 'o-drop--expanded')]:
            this.expanded,
        },
        { [this.computedClass('inlineClass', 'o-drop--inline')]: this.inline },
        {
          [this.computedClass('mobileClass', 'o-drop--mobile')]:
            this.isMobileModal && this.isMatchMedia && !this.hoverable,
        },
      ]
    },
    menuClasses() {
      return [
        this.computedClass('menuClass', 'o-drop__menu'),
        {
          [this.computedClass(
            'menuPositionClass',
            'o-drop__menu--',
            this.autoPosition,
          )]: this.autoPosition,
        },
        {
          [this.computedClass('menuActiveClass', 'o-drop__menu--active')]:
            this.isActive || this.inline,
        },
        {
          [this.computedClass('menuShadowClass', 'no-shadow')]: this.noShadow,
        },
        {
          [this.computedClass(
            'menuScrollableClass',
            'o-drop__menu--scrollable',
          )]: this.scrollable,
        },
      ]
    },
    isAutoPosition() {
      return this.position?.includes('auto')
    },
  },
  mounted() {
    if (this.isAutoPosition) {
      this.calcDropdownPosition()
      window.addEventListener('resize', this.calcDropdownPosition)
    }
    else {
      this.autoPosition = this.position
    }
    if (this.closeMenuOnMove) {
      watch(useElementBounding(this.$refs.trigger).top, this.onTriggerMove)
    }
  },
  onBeforeUnmount() {
    window.removeEventListener('resize', this.calcDropdownPosition)
  },
  methods: {
    calcDropdownPosition() {
      // support pass `position` type of `top-auto` or `bottom-auto`
      // calc the dropdown position based on the trigger position
      const ele = this.$refs.trigger
      const side
        = ele?.getBoundingClientRect().left < window.innerWidth / 2
          ? 'right'
          : 'left'
      this.autoPosition = this.position.replace('auto', side)
    },
    onTriggerMove() {
      if (this.isActive) {
        this.isActive = false
      }
    },
  },
}
</script>

<style lang="scss">
@import './NeoDropdown.scss';
</style>