visua-vue/src/components/checkbox/VCheckbox.vue
2025-07-23 12:39:02 +02:00

173 lines
4.7 KiB
Vue

<script setup lang="ts">
import Checkbox from 'primevue/checkbox';
import VLabel from '../label/VLabel.vue';
import VHint from '../hint/VHint.vue';
import type IVCheckBox from './IVCheckbox.type';
import { useId, computed, watch, ref } from 'vue';
const props = withDefaults(defineProps<IVCheckBox>(), {
id: () => useId(),
hint: '',
errorMessage: '',
validMessage: '',
label: '',
small: false,
modelValue: false,
readonlyOpacity: 0.75,
});
const size = computed(() => props.small ? 'small' : undefined)
const message = computed(() => props.errorMessage || props.validMessage)
const typeMessage = computed(() => {
if (props.errorMessage) return 'alert';
else if (props.validMessage) return 'success';
else return undefined
});
const binary = computed(() => {
if (typeof props.binary === 'boolean') return props.binary;
return typeof props.modelValue === 'boolean';
});
const labelState = computed(() => {
if((!!props.errorMessage || props.type === 'error') && !props.disabled) return 'error';
else if((!!props.validMessage || props.type === 'success') && !props.disabled) return 'success';
else return 'default';
})
const emit = defineEmits([
'update:modelValue',
'value-change',
'change',
'focus',
'blur'
])
const localModelValue = ref(props.modelValue);
watch(() => props.modelValue, (newVal) => {
if(localModelValue.value !== newVal){
localModelValue.value = newVal;
}
})
watch(localModelValue, (newVal) => {
if(props.modelValue !== newVal){
emit('update:modelValue', newVal);
}
});
</script>
<template>
<div class="checkbox-container">
<div class="header">
<Checkbox
:id="props.id"
:name="name"
:value="value"
:size="size"
:required="required"
:readonly="readonly"
:data-testid="`input-checkbox-${id}`"
:data-test="`input-checkbox-${id}`"
:tabindex="readonly ? -1 : undefined"
v-bind="$attrs"
:disabled="disabled"
:label="props.label"
:binary="binary"
:aria-label="props.label"
:class="['p-checkbox', {
'checked-disabled': props.modelValue && disabled,
'unchecked-disabled': !props.modelValue && disabled,
'error': (!!props.errorMessage || type === 'error') && !disabled,
'success': (!!props.validMessage || type === 'success') && !disabled,
}]"
v-model:model-value="localModelValue"
@update:model-value="emit('update:modelValue', $event)"
@change="emit('change', $event)"
@blur="emit('blur', $event)"
@focus="emit('focus', $event)"
@value-change="emit('value-change', $event)"
/>
<VLabel
:for="props.id"
:label="props.label"
:required="props.required"
:disabled="props.disabled"
:hint="props.hint"
:type="labelState"
class="label-container"
>
<template #required-tip v-if="props.required">
<slot name="required-tip"/>
</template>
</VLabel>
</div>
<div
v-if="message && !disabled"
aria-live="assertive"
role="alert"
>
<VHint :title="message" :type="typeMessage" icon/>
</div>
</div>
</template>
<style scoped>
.container.readonly {
pointer-events: none;
cursor: not-allowed;
opacity: v-bind('readonlyOpacity');
}
.checkbox-container {
width: 100%;
display: flex;
flex-direction: column;
align-items: start;
gap: 0.5rem;
align-self: stretch;
}
.header{
display: flex;
flex-direction: row;
align-items: start;
gap: 0.5rem;
padding: 0px;
}
.p-checkbox{margin-top: 0.5rem;}
.required {color: var(--minor-red-marianne);}
.p-checkbox.checked-disabled {
--p-checkbox-disabled-background: var(--background-disabled-grey);
--p-checkbox-checked-disabled-border-color: var(--border-disabled-grey);
--p-checkbox-icon-disabled-color: var(--text-disabled-grey);
}
.p-checkbox.unchecked-disabled {
--p-checkbox-disabled-background: var(--background-default-grey);
--p-checkbox-checked-disabled-border-color: var(--border-disabled-grey);
}
.p-checkbox.success {
--p-checkbox-border-color: var(--border-plain-success);
--p-checkbox-hover-border-color: var(--border-plain-success);
--p-checkbox-focus-border-color: var(--border-plain-success);
--p-checkbox-checked-border-color: var(--border-plain-success);
--p-checkbox-checked-hover-border-color: var(--border-plain-success);
outline: var(--border-width) solid var(--p-checkbox-border-color);
}
.p-checkbox.error {
--p-checkbox-border-color: var(--border-plain-error);
--p-checkbox-hover-border-color: var(--border-plain-error);
--p-checkbox-focus-border-color: var(--border-plain-error);
--p-checkbox-checked-border-color: var(--border-plain-error);
--p-checkbox-checked-hover-border-color: var(--border-plain-error);
outline: var(--border-width) solid var(--p-checkbox-border-color);
}
</style>