123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- import { withDirectives as _withDirectives, resolveDirective as _resolveDirective, Fragment as _Fragment, createVNode as _createVNode, mergeProps as _mergeProps } from "vue";
- // Styles
- import "./VSelectionControl.css";
- // Components
- import { VIcon } from "../VIcon/index.mjs";
- import { VLabel } from "../VLabel/index.mjs";
- import { makeSelectionControlGroupProps, VSelectionControlGroupSymbol } from "../VSelectionControlGroup/VSelectionControlGroup.mjs"; // Composables
- import { useBackgroundColor, useTextColor } from "../../composables/color.mjs";
- import { makeComponentProps } from "../../composables/component.mjs";
- import { useDensity } from "../../composables/density.mjs";
- import { useProxiedModel } from "../../composables/proxiedModel.mjs"; // Directives
- import { Ripple } from "../../directives/ripple/index.mjs"; // Utilities
- import { computed, inject, nextTick, ref, shallowRef } from 'vue';
- import { filterInputAttrs, genericComponent, getUid, matchesSelector, propsFactory, useRender, wrapInArray } from "../../util/index.mjs"; // 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(computed(() => {
- if (props.error || props.disabled) return undefined;
- return model.value ? props.color : props.baseColor;
- }));
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(computed(() => {
- 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: {
- Ripple
- },
- 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 = getUid();
- const isFocused = shallowRef(false);
- const isFocusVisible = shallowRef(false);
- const input = ref();
- const id = computed(() => props.id || `input-${uid}`);
- const isInteractive = computed(() => !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 = _createVNode("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 _createVNode("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
- }), [_createVNode("div", {
- "class": ['v-selection-control__wrapper', textColorClasses.value],
- "style": textColorStyles.value
- }, [slots.default?.({
- backgroundColorClasses,
- backgroundColorStyles
- }), _withDirectives(_createVNode("div", {
- "class": ['v-selection-control__input']
- }, [slots.input?.({
- model,
- textColorClasses,
- textColorStyles,
- backgroundColorClasses,
- backgroundColorStyles,
- inputNode,
- icon: icon.value,
- props: {
- onFocus,
- onBlur,
- id: id.value
- }
- }) ?? _createVNode(_Fragment, null, [icon.value && _createVNode(VIcon, {
- "key": "icon",
- "icon": icon.value
- }, null), inputNode])]), [[_resolveDirective("ripple"), props.ripple && [!props.disabled && !props.readonly, null, ['center', 'circle']]]])]), label && _createVNode(VLabel, {
- "for": id.value,
- "onClick": onClickLabel
- }, {
- default: () => [label]
- })]);
- });
- return {
- isFocused,
- input
- };
- }
- });
- //# sourceMappingURL=VSelectionControl.mjs.map
|