@coreui/vue-pro
Version:
UI Components Library for Vue.js
171 lines (154 loc) • 4.18 kB
text/typescript
import { cloneVNode, defineComponent, h, PropType, ref, watch } from 'vue'
import { createPopper } from '@popperjs/core'
import { isRTL } from '../../utils'
const CPicker = defineComponent({
name: 'CPicker',
props: {
/**
* Set container type for the component.
*/
container: {
type: String as PropType<'dropdown' | 'inline'>,
default: 'dropdown',
},
/**
* Toggle the disabled state for the component.
*/
disabled: Boolean,
/**
* A string of all className you want applied to the dropdown menu.
*/
dropdownClassNames: String,
/**
* Toggle visibility of footer element or set the content of footer.
*/
footer: Boolean,
/**
* Toggle the visibility of the component.
*/
visible: Boolean,
},
emits: [
/**
* Callback fired when the component requests to be hidden.
*/
'hide',
/**
* Callback fired when the component requests to be shown.
*/
'show',
],
setup(props, { attrs, emit, slots }) {
const pickerRef = ref()
const dropdownRef = ref()
const togglerRef = ref()
const popper = ref()
const visible = ref(props.visible)
watch(
() => props.visible,
() => {
visible.value = props.visible
},
)
watch(visible, () => {
if (props.container === 'inline') {
return
}
if (visible.value) {
emit('show')
window.addEventListener('mouseup', handleMouseUp)
window.addEventListener('keyup', handleKeyUp)
initPopper()
return
}
emit('hide')
window.removeEventListener('mouseup', handleMouseUp)
window.removeEventListener('keyup', handleKeyUp)
destroyPopper()
})
const initPopper = () => {
if (togglerRef.value && dropdownRef.value) {
popper.value = createPopper(togglerRef.value, dropdownRef.value, {
placement: isRTL(pickerRef.value) ? 'bottom-end' : 'bottom-start',
modifiers: [
{
name: 'preventOverflow',
options: {
boundary: 'clippingParents',
},
},
{
name: 'offset',
options: {
offset: [0, 2],
},
},
],
})
}
}
const destroyPopper = () => {
if (popper.value) {
popper.value.destroy()
}
popper.value = undefined
}
const handleKeyUp = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
visible.value = false
}
}
const handleMouseUp = (event: Event) => {
if (pickerRef.value && pickerRef.value.contains(event.target as HTMLElement)) {
return
}
visible.value = false
}
switch (props.container) {
case 'inline': {
return () => h('div', { class: 'picker', ref: pickerRef }, slots.default && slots.default())
}
default: {
return () =>
h(
'div',
{
class: [
attrs.class,
{
show: visible.value,
},
],
ref: pickerRef,
},
[
/**
* @slot Location for the toggler element.
*/
slots.toggler &&
slots.toggler().map((slot) =>
cloneVNode(slot, {
onClick: () => {
if (!props.disabled && !visible.value) {
visible.value = true
}
},
ref: (el) => {
togglerRef.value = el
},
}),
),
h('div', { class: props.dropdownClassNames, ref: dropdownRef }, [
slots.default && slots.default(),
/**
* @slot Location for the footer element.
*/
props.footer && slots.footer && slots.footer(),
]),
],
)
}
}
},
})
export { CPicker }