UNPKG

quasar

Version:

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

274 lines (226 loc) 6.52 kB
import { h, ref, computed, getCurrentInstance, toRaw } from 'vue' import useDark, { useDarkProps } from '../../composables/private.use-dark/use-dark.js' import useSize, { useSizeProps } from '../../composables/private.use-size/use-size.js' import useRefocusTarget from '../../composables/private.use-refocus-target/use-refocus-target.js' import { useFormInject, useFormProps } from '../../composables/use-form/private.use-form.js' import optionSizes from '../../utils/private.option-sizes/option-sizes.js' import { stopAndPrevent } from '../../utils/event/event.js' import { hSlot, hMergeSlot } from '../../utils/private.render/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 useCheckbox(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' } if (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() if (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) if (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 ) } }