quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
172 lines (139 loc) • 4.41 kB
JavaScript
import { h, computed, getCurrentInstance } from 'vue'
import QRadio from '../radio/QRadio.js'
import QCheckbox from '../checkbox/QCheckbox.js'
import QToggle from '../toggle/QToggle.js'
import { createComponent } from '../../utils/private.create/create.js'
import useDark, {
useDarkProps
} from '../../composables/private.use-dark/use-dark.js'
import { isObject } from '../../utils/is/is.js'
const components = {
radio: QRadio,
checkbox: QCheckbox,
toggle: QToggle
}
const typeValues = Object.keys(components)
function getPropValueFn(userPropName, defaultPropName) {
if (typeof userPropName === 'function') return userPropName
const propName = userPropName !== void 0 ? userPropName : defaultPropName
return opt => opt[propName]
}
export default createComponent({
name: 'QOptionGroup',
props: {
...useDarkProps,
modelValue: {
required: true
},
options: {
type: Array,
validator: opts => opts.every(isObject),
default: () => []
},
optionValue: [Function, String],
optionLabel: [Function, String],
optionDisable: [Function, String],
name: String,
type: {
type: String,
default: 'radio',
validator: v => typeValues.includes(v)
},
color: String,
keepColor: Boolean,
dense: Boolean,
size: String,
leftLabel: Boolean,
inline: Boolean,
disable: Boolean
},
emits: ['update:modelValue'],
setup(props, { emit, slots }) {
const {
proxy: { $q }
} = getCurrentInstance()
const arrayModel = Array.isArray(props.modelValue)
if (props.type === 'radio') {
if (arrayModel === true) {
console.error('q-option-group: model should not be array')
}
} else if (arrayModel === false) {
console.error('q-option-group: model should be array in your case')
}
const isDark = useDark(props, $q)
const component = computed(() => components[props.type])
const getOptionValue = computed(() =>
getPropValueFn(props.optionValue, 'value')
)
const getOptionLabel = computed(() =>
getPropValueFn(props.optionLabel, 'label')
)
const getOptionDisable = computed(() =>
getPropValueFn(props.optionDisable, 'disable')
)
const innerOptions = computed(() =>
props.options.map(opt => ({
val: getOptionValue.value(opt),
name: opt.name === void 0 ? props.name : opt.name,
disable: props.disable || getOptionDisable.value(opt),
leftLabel: opt.leftLabel === void 0 ? props.leftLabel : opt.leftLabel,
color: opt.color === void 0 ? props.color : opt.color,
checkedIcon: opt.checkedIcon,
uncheckedIcon: opt.uncheckedIcon,
dark: opt.dark === void 0 ? isDark.value : opt.dark,
size: opt.size === void 0 ? props.size : opt.size,
dense: props.dense,
keepColor: opt.keepColor === void 0 ? props.keepColor : opt.keepColor
}))
)
const classes = computed(
() =>
'q-option-group q-gutter-x-sm' +
(props.inline === true ? ' q-option-group--inline' : '')
)
const attrs = computed(() => {
const acc = { role: 'group' }
if (props.type === 'radio') {
acc.role = 'radiogroup'
if (props.disable === true) {
acc['aria-disabled'] = 'true'
}
}
return acc
})
function onUpdateModelValue(value) {
emit('update:modelValue', value)
}
return () =>
h(
'div',
{
class: classes.value,
...attrs.value
},
props.options.map((opt, i) => {
// TODO: (Qv3) Make the 'opt' a separate property instead of
// the whole scope for consistency and flexibility
// (e.g. { opt } instead of opt)
const child =
slots['label-' + i] !== void 0
? () => slots['label-' + i](opt)
: slots.label !== void 0
? () => slots.label(opt)
: void 0
return h('div', [
h(
component.value,
{
label: child === void 0 ? getOptionLabel.value(opt) : null,
modelValue: props.modelValue,
'onUpdate:modelValue': onUpdateModelValue,
...innerOptions.value[i]
},
child
)
])
})
)
}
})