UNPKG

vuetify

Version:

Vue Material Component Framework

217 lines (216 loc) 7.63 kB
import { mergeProps as _mergeProps, createElementVNode as _createElementVNode, Fragment as _Fragment, createVNode as _createVNode, withDirectives as _withDirectives, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle } from "vue"; // Styles import "./VSelectionControl.css"; // Components import { VIcon } from "../VIcon/index.js"; import { VLabel } from "../VLabel/index.js"; import { makeSelectionControlGroupProps, VSelectionControlGroupSymbol } from "../VSelectionControlGroup/VSelectionControlGroup.js"; // Composables import { useBackgroundColor, useTextColor } from "../../composables/color.js"; import { makeComponentProps } from "../../composables/component.js"; import { useDensity } from "../../composables/density.js"; import { useProxiedModel } from "../../composables/proxiedModel.js"; // Directives import vRipple from "../../directives/ripple/index.js"; // Utilities import { computed, inject, nextTick, ref, shallowRef, toRef, useId } from 'vue'; import { filterInputAttrs, genericComponent, matchesSelector, propsFactory, useRender, wrapInArray } from "../../util/index.js"; // Types export const makeVSelectionControlProps = propsFactory({ label: String, baseColor: String, trueValue: null, falseValue: null, value: null, ...makeComponentProps(), ...makeSelectionControlGroupProps() }, 'VSelectionControl'); export function useSelectionControl(props) { const group = inject(VSelectionControlGroupSymbol, undefined); const { densityClasses } = useDensity(props); const modelValue = useProxiedModel(props, 'modelValue'); const trueValue = computed(() => props.trueValue !== undefined ? props.trueValue : props.value !== undefined ? props.value : true); const falseValue = computed(() => props.falseValue !== undefined ? props.falseValue : false); const isMultiple = computed(() => !!props.multiple || props.multiple == null && Array.isArray(modelValue.value)); const model = computed({ get() { const val = group ? group.modelValue.value : modelValue.value; return isMultiple.value ? wrapInArray(val).some(v => props.valueComparator(v, trueValue.value)) : props.valueComparator(val, trueValue.value); }, set(val) { if (props.readonly) return; const currentValue = val ? trueValue.value : falseValue.value; let newVal = currentValue; if (isMultiple.value) { newVal = val ? [...wrapInArray(modelValue.value), currentValue] : wrapInArray(modelValue.value).filter(item => !props.valueComparator(item, trueValue.value)); } if (group) { group.modelValue.value = newVal; } else { modelValue.value = newVal; } } }); const { textColorClasses, textColorStyles } = useTextColor(() => { if (props.error || props.disabled) return undefined; return model.value ? props.color : props.baseColor; }); const { backgroundColorClasses, backgroundColorStyles } = useBackgroundColor(() => { return model.value && !props.error && !props.disabled ? props.color : props.baseColor; }); const icon = computed(() => model.value ? props.trueIcon : props.falseIcon); return { group, densityClasses, trueValue, falseValue, model, textColorClasses, textColorStyles, backgroundColorClasses, backgroundColorStyles, icon }; } export const VSelectionControl = genericComponent()({ name: 'VSelectionControl', directives: { vRipple }, inheritAttrs: false, props: makeVSelectionControlProps(), emits: { 'update:modelValue': value => true }, setup(props, _ref) { let { attrs, slots } = _ref; const { group, densityClasses, icon, model, textColorClasses, textColorStyles, backgroundColorClasses, backgroundColorStyles, trueValue } = useSelectionControl(props); const uid = useId(); const isFocused = shallowRef(false); const isFocusVisible = shallowRef(false); const input = ref(); const id = toRef(() => props.id || `input-${uid}`); const isInteractive = toRef(() => !props.disabled && !props.readonly); group?.onForceUpdate(() => { if (input.value) { input.value.checked = model.value; } }); function onFocus(e) { if (!isInteractive.value) return; isFocused.value = true; if (matchesSelector(e.target, ':focus-visible') !== false) { isFocusVisible.value = true; } } function onBlur() { isFocused.value = false; isFocusVisible.value = false; } function onClickLabel(e) { e.stopPropagation(); } function onInput(e) { if (!isInteractive.value) { if (input.value) { // model value is not updated when input is not interactive // but the internal checked state of the input is still updated, // so here it's value is restored input.value.checked = model.value; } return; } if (props.readonly && group) { nextTick(() => group.forceUpdate()); } model.value = e.target.checked; } useRender(() => { const label = slots.label ? slots.label({ label: props.label, props: { for: id.value } }) : props.label; const [rootAttrs, inputAttrs] = filterInputAttrs(attrs); const inputNode = _createElementVNode("input", _mergeProps({ "ref": input, "checked": model.value, "disabled": !!props.disabled, "id": id.value, "onBlur": onBlur, "onFocus": onFocus, "onInput": onInput, "aria-disabled": !!props.disabled, "aria-label": props.label, "type": props.type, "value": trueValue.value, "name": props.name, "aria-checked": props.type === 'checkbox' ? model.value : undefined }, inputAttrs), null); return _createElementVNode("div", _mergeProps({ "class": ['v-selection-control', { 'v-selection-control--dirty': model.value, 'v-selection-control--disabled': props.disabled, 'v-selection-control--error': props.error, 'v-selection-control--focused': isFocused.value, 'v-selection-control--focus-visible': isFocusVisible.value, 'v-selection-control--inline': props.inline }, densityClasses.value, props.class] }, rootAttrs, { "style": props.style }), [_createElementVNode("div", { "class": _normalizeClass(['v-selection-control__wrapper', textColorClasses.value]), "style": _normalizeStyle(textColorStyles.value) }, [slots.default?.({ backgroundColorClasses, backgroundColorStyles }), _withDirectives(_createElementVNode("div", { "class": ['v-selection-control__input'] }, [slots.input?.({ model, textColorClasses, textColorStyles, backgroundColorClasses, backgroundColorStyles, inputNode, icon: icon.value, props: { onFocus, onBlur, id: id.value } }) ?? _createElementVNode(_Fragment, null, [icon.value && _createVNode(VIcon, { "key": "icon", "icon": icon.value }, null), inputNode])]), [[vRipple, props.ripple && [!props.disabled && !props.readonly, null, ['center', 'circle']]]])]), label && _createVNode(VLabel, { "for": id.value, "onClick": onClickLabel }, { default: () => [label] })]); }); return { isFocused, input }; } }); //# sourceMappingURL=VSelectionControl.js.map