UNPKG

@coreui/vue-pro

Version:

UI Components Library for Vue.js

213 lines (194 loc) 5.57 kB
import { cloneVNode, defineComponent, h, PropType, ref, watch } from 'vue' import { createPopper } from '@popperjs/core' import { CConditionalTeleport } from '../conditional-teleport' import { CFocusTrap } from '../focus-trap' 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, /** * Generates dropdown menu using Teleport. * * @since 5.8.0 */ teleport: { type: [Boolean], default: false, }, /** * 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 } if (dropdownRef.value && dropdownRef.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( CFocusTrap, { active: visible.value, ...(props.teleport && { additionalContainer: dropdownRef }) }, () => 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( CConditionalTeleport, { teleport: props.teleport, }, { default: () => h( 'div', { class: [ props.dropdownClassNames, { show: props.teleport && visible.value, }, ], ref: dropdownRef, }, [ slots.default && slots.default(), /** * @slot Location for the footer element. */ props.footer && slots.footer && slots.footer(), ] ), } ), ] ) ) } } }, }) export { CPicker }