UNPKG

quasar

Version:

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

245 lines (197 loc) 6.2 kB
import { h, ref, computed, getCurrentInstance, toRaw } from 'vue' import useDark, { useDarkProps } from '../../composables/private/use-dark.js' import useSize, { useSizeProps } from '../../composables/private/use-size.js' import useRefocusTarget from '../../composables/private/use-refocus-target.js' import { useFormInject, useFormProps } from '../../composables/private/use-form.js' import optionSizes from '../../utils/private/option-sizes.js' import { stopAndPrevent } from '../../utils/event.js' import { hSlot, hMergeSlot } from '../../utils/private/render.js' export const useCheckboxProps = { ...useDarkProps, ...useSizeProps, ...useFormProps, modelValue: { required: true, default: null }, val: {}, trueValue: { default: true }, falseValue: { default: false }, indeterminateValue: { default: null }, checkedIcon: String, uncheckedIcon: String, indeterminateIcon: String, toggleOrder: { type: String, validator: v => v === 'tf' || v === 'ft' }, toggleIndeterminate: Boolean, label: String, leftLabel: Boolean, color: String, keepColor: Boolean, dense: Boolean, disable: Boolean, tabindex: [ String, Number ] } export const useCheckboxEmits = [ 'update:modelValue' ] export default function (type, getInner) { const { props, slots, emit, proxy } = getCurrentInstance() const { $q } = proxy const isDark = useDark(props, $q) const rootRef = ref(null) const { refocusTargetEl, refocusTarget } = useRefocusTarget(props, rootRef) const sizeStyle = useSize(props, optionSizes) const modelIsArray = computed(() => props.val !== void 0 && Array.isArray(props.modelValue) ) const index = computed(() => { const val = toRaw(props.val) return modelIsArray.value === true ? props.modelValue.findIndex(opt => toRaw(opt) === val) : -1 }) const isTrue = computed(() => ( modelIsArray.value === true ? index.value > -1 : toRaw(props.modelValue) === toRaw(props.trueValue) )) const isFalse = computed(() => ( modelIsArray.value === true ? index.value === -1 : toRaw(props.modelValue) === toRaw(props.falseValue) )) const isIndeterminate = computed(() => isTrue.value === false && isFalse.value === false ) const tabindex = computed(() => ( props.disable === true ? -1 : props.tabindex || 0 )) const classes = computed(() => `q-${ type } cursor-pointer no-outline row inline no-wrap items-center` + (props.disable === true ? ' disabled' : '') + (isDark.value === true ? ` q-${ type }--dark` : '') + (props.dense === true ? ` q-${ type }--dense` : '') + (props.leftLabel === true ? ' reverse' : '') ) const innerClass = computed(() => { const state = isTrue.value === true ? 'truthy' : (isFalse.value === true ? 'falsy' : 'indet') const color = props.color !== void 0 && ( props.keepColor === true || (type === 'toggle' ? isTrue.value === true : isFalse.value !== true) ) ? ` text-${ props.color }` : '' return `q-${ type }__inner relative-position non-selectable q-${ type }__inner--${ state }${ color }` }) const formAttrs = computed(() => { const prop = { type: 'checkbox' } props.name !== void 0 && Object.assign(prop, { // see https://vuejs.org/guide/extras/render-function.html#creating-vnodes (.prop) '.checked': isTrue.value, '^checked': isTrue.value === true ? 'checked' : void 0, name: props.name, value: modelIsArray.value === true ? props.val : props.trueValue }) return prop }) const injectFormInput = useFormInject(formAttrs) const attributes = computed(() => { const attrs = { tabindex: tabindex.value, role: type === 'toggle' ? 'switch' : 'checkbox', 'aria-label': props.label, 'aria-checked': isIndeterminate.value === true ? 'mixed' : (isTrue.value === true ? 'true' : 'false') } if (props.disable === true) { attrs[ 'aria-disabled' ] = 'true' } return attrs }) function onClick (e) { if (e !== void 0) { stopAndPrevent(e) refocusTarget(e) } if (props.disable !== true) { emit('update:modelValue', getNextValue(), e) } } function getNextValue () { if (modelIsArray.value === true) { if (isTrue.value === true) { const val = props.modelValue.slice() val.splice(index.value, 1) return val } return props.modelValue.concat([ props.val ]) } if (isTrue.value === true) { if (props.toggleOrder !== 'ft' || props.toggleIndeterminate === false) { return props.falseValue } } else if (isFalse.value === true) { if (props.toggleOrder === 'ft' || props.toggleIndeterminate === false) { return props.trueValue } } else { return props.toggleOrder !== 'ft' ? props.trueValue : props.falseValue } return props.indeterminateValue } function onKeydown (e) { if (e.keyCode === 13 || e.keyCode === 32) { stopAndPrevent(e) } } function onKeyup (e) { if (e.keyCode === 13 || e.keyCode === 32) { onClick(e) } } const getInnerContent = getInner(isTrue, isIndeterminate) // expose public methods Object.assign(proxy, { toggle: onClick }) return () => { const inner = getInnerContent() props.disable !== true && injectFormInput( inner, 'unshift', ` q-${ type }__native absolute q-ma-none q-pa-none` ) const child = [ h('div', { class: innerClass.value, style: sizeStyle.value, 'aria-hidden': 'true' }, inner) ] if (refocusTargetEl.value !== null) { child.push(refocusTargetEl.value) } const label = props.label !== void 0 ? hMergeSlot(slots.default, [ props.label ]) : hSlot(slots.default) label !== void 0 && child.push( h('div', { class: `q-${ type }__label q-anchor--skip` }, label) ) return h('div', { ref: rootRef, class: classes.value, ...attributes.value, onClick, onKeydown, onKeyup }, child) } }