UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

246 lines (205 loc) 6.44 kB
import { h, ref, computed, watch, onMounted, getCurrentInstance } from 'vue' import QIcon from '../icon/QIcon.js' import QBtn from '../btn/QBtn.js' import QBtnGroup from '../btn-group/QBtnGroup.js' import QMenu from '../menu/QMenu.js' import { getBtnDesignAttr, nonRoundBtnProps } from '../btn/use-btn.js' import useId from '../../composables/use-id/use-id.js' import { useTransitionProps } from '../../composables/private.use-transition/use-transition.js' import { createComponent } from '../../utils/private.create/create.js' import { stop } from '../../utils/event/event.js' import { hSlot } from '../../utils/private.render/render.js' const btnPropsList = Object.keys(nonRoundBtnProps) export function passBtnProps (props) { return btnPropsList.reduce((acc, key) => { const val = props[ key ] if (val !== void 0) { acc[ key ] = val } return acc }, {}) } export default createComponent({ name: 'QBtnDropdown', props: { ...nonRoundBtnProps, ...useTransitionProps, modelValue: Boolean, split: Boolean, dropdownIcon: String, contentClass: [ Array, String, Object ], contentStyle: [ Array, String, Object ], cover: Boolean, persistent: Boolean, noRouteDismiss: Boolean, autoClose: Boolean, menuAnchor: { type: String, default: 'bottom end' }, menuSelf: { type: String, default: 'top end' }, menuOffset: Array, disableMainBtn: Boolean, disableDropdown: Boolean, noIconAnimation: Boolean, toggleAriaLabel: String }, emits: [ 'update:modelValue', 'click', 'beforeShow', 'show', 'beforeHide', 'hide' ], setup (props, { slots, emit }) { const { proxy } = getCurrentInstance() const showing = ref(props.modelValue) const menuRef = ref(null) const targetUid = useId() const ariaAttrs = computed(() => { const acc = { 'aria-expanded': showing.value === true ? 'true' : 'false', 'aria-haspopup': 'true', 'aria-controls': targetUid.value, 'aria-label': props.toggleAriaLabel || proxy.$q.lang.label[ showing.value === true ? 'collapse' : 'expand' ](props.label) } if ( props.disable === true || ( (props.split === false && props.disableMainBtn === true) || props.disableDropdown === true ) ) { acc[ 'aria-disabled' ] = 'true' } return acc }) const iconClass = computed(() => 'q-btn-dropdown__arrow' + (showing.value === true && props.noIconAnimation === false ? ' rotate-180' : '') + (props.split === false ? ' q-btn-dropdown__arrow-container' : '') ) const btnDesignAttr = computed(() => getBtnDesignAttr(props)) const btnProps = computed(() => passBtnProps(props)) watch(() => props.modelValue, val => { menuRef.value !== null && menuRef.value[ val ? 'show' : 'hide' ]() }) watch(() => props.split, hide) function onBeforeShow (e) { showing.value = true emit('beforeShow', e) } function onShow (e) { emit('show', e) emit('update:modelValue', true) } function onBeforeHide (e) { showing.value = false emit('beforeHide', e) } function onHide (e) { emit('hide', e) emit('update:modelValue', false) } function onClick (e) { emit('click', e) } function onClickHide (e) { stop(e) hide() emit('click', e) } function toggle (evt) { menuRef.value !== null && menuRef.value.toggle(evt) } function show (evt) { menuRef.value !== null && menuRef.value.show(evt) } function hide (evt) { menuRef.value !== null && menuRef.value.hide(evt) } // expose public methods Object.assign(proxy, { show, hide, toggle }) onMounted(() => { props.modelValue === true && show() }) return () => { const Arrow = [ h(QIcon, { class: iconClass.value, name: props.dropdownIcon || proxy.$q.iconSet.arrow.dropdown }) ] props.disableDropdown !== true && Arrow.push( h(QMenu, { ref: menuRef, id: targetUid.value, class: props.contentClass, style: props.contentStyle, cover: props.cover, fit: true, persistent: props.persistent, noRouteDismiss: props.noRouteDismiss, autoClose: props.autoClose, anchor: props.menuAnchor, self: props.menuSelf, offset: props.menuOffset, separateClosePopup: true, transitionShow: props.transitionShow, transitionHide: props.transitionHide, transitionDuration: props.transitionDuration, onBeforeShow, onShow, onBeforeHide, onHide }, slots.default) ) if (props.split === false) { return h(QBtn, { class: 'q-btn-dropdown q-btn-dropdown--simple', ...btnProps.value, ...ariaAttrs.value, disable: props.disable === true || props.disableMainBtn === true, noWrap: true, round: false, onClick }, { default: () => hSlot(slots.label, []).concat(Arrow), loading: slots.loading }) } return h(QBtnGroup, { class: 'q-btn-dropdown q-btn-dropdown--split no-wrap q-btn-item', rounded: props.rounded, square: props.square, ...btnDesignAttr.value, glossy: props.glossy, stretch: props.stretch }, () => [ h(QBtn, { class: 'q-btn-dropdown--current', ...btnProps.value, disable: props.disable === true || props.disableMainBtn === true, noWrap: true, round: false, onClick: onClickHide }, { default: slots.label, loading: slots.loading }), h(QBtn, { class: 'q-btn-dropdown__arrow-container q-anchor--skip', ...ariaAttrs.value, ...btnDesignAttr.value, disable: props.disable === true || props.disableDropdown === true, rounded: props.rounded, color: props.color, textColor: props.textColor, dense: props.dense, size: props.size, padding: props.padding, ripple: props.ripple }, () => Arrow) ]) } } })