mirror of https://github.com/FreeTubeApp/FreeTube
151 lines
3.4 KiB
JavaScript
151 lines
3.4 KiB
JavaScript
import { defineComponent } from 'vue'
|
|
import FtPrompt from '../ft-prompt/ft-prompt.vue'
|
|
import { sanitizeForHtmlId } from '../../helpers/accessibility'
|
|
|
|
export default defineComponent({
|
|
name: 'FtIconButton',
|
|
components: {
|
|
'ft-prompt': FtPrompt
|
|
},
|
|
props: {
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
icon: {
|
|
type: Array,
|
|
default: () => ['fas', 'ellipsis-v']
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
theme: {
|
|
type: String,
|
|
default: 'base'
|
|
},
|
|
useShadow: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
padding: {
|
|
type: Number,
|
|
default: 10
|
|
},
|
|
size: {
|
|
type: Number,
|
|
default: 20
|
|
},
|
|
forceDropdown: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
returnIndex: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
dropdownPositionX: {
|
|
type: String,
|
|
default: 'center'
|
|
},
|
|
dropdownPositionY: {
|
|
type: String,
|
|
default: 'bottom'
|
|
},
|
|
dropdownOptions: {
|
|
// Array of objects with these properties
|
|
// - type: ('labelValue'|'divider', default to 'labelValue' for less typing)
|
|
// - label: String (if type == 'labelValue')
|
|
// - value: String (if type == 'labelValue')
|
|
type: Array,
|
|
default: () => { return [] }
|
|
},
|
|
dropdownModalOnMobile: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
emits: ['click'],
|
|
data: function () {
|
|
return {
|
|
dropdownShown: false,
|
|
mouseDownOnIcon: false,
|
|
useModal: false
|
|
}
|
|
},
|
|
mounted: function () {
|
|
if (this.dropdownModalOnMobile) {
|
|
this.useModal = window.innerWidth <= 900
|
|
window.addEventListener('resize', this.handleResize)
|
|
}
|
|
},
|
|
beforeDestroy: function () {
|
|
if (this.dropdownModalOnMobile) {
|
|
window.removeEventListener('resize', this.handleResize)
|
|
}
|
|
},
|
|
methods: {
|
|
sanitizeForHtmlId,
|
|
// used by the share menu
|
|
hideDropdown: function () {
|
|
this.dropdownShown = false
|
|
},
|
|
|
|
handleIconClick: function () {
|
|
if (this.disabled) { return }
|
|
if (this.forceDropdown || (this.dropdownOptions.length > 0)) {
|
|
this.dropdownShown = !this.dropdownShown
|
|
|
|
if (this.dropdownShown && !this.useModal) {
|
|
// wait until the dropdown is visible
|
|
// then focus it so we can hide it automatically when it loses focus
|
|
setTimeout(() => {
|
|
this.$refs.dropdown?.focus()
|
|
})
|
|
}
|
|
} else {
|
|
this.$emit('click')
|
|
}
|
|
},
|
|
|
|
handleIconMouseDown: function () {
|
|
if (this.disabled) { return }
|
|
if (this.dropdownShown) {
|
|
this.mouseDownOnIcon = true
|
|
}
|
|
},
|
|
|
|
handleDropdownFocusOut: function () {
|
|
if (this.mouseDownOnIcon) {
|
|
this.mouseDownOnIcon = false
|
|
} else if (!this.$refs.dropdown.matches(':focus-within')) {
|
|
this.dropdownShown = false
|
|
}
|
|
},
|
|
|
|
handleDropdownEscape: function () {
|
|
this.$refs.iconButton.focus()
|
|
// handleDropdownFocusOut will hide the dropdown for us
|
|
},
|
|
|
|
handleDropdownClick: function ({ url, index }) {
|
|
if (this.returnIndex) {
|
|
this.$emit('click', index)
|
|
} else {
|
|
this.$emit('click', url)
|
|
}
|
|
|
|
this.dropdownShown = false
|
|
},
|
|
|
|
handleResize: function () {
|
|
this.useModal = window.innerWidth <= 900
|
|
},
|
|
|
|
focus() {
|
|
// To be called by parent components
|
|
this.$refs.iconButton.focus()
|
|
},
|
|
}
|
|
})
|