Files
ppeasy_vg12/resources/js/components/ui/Checkbox.vue
T
2026-10-09 08:21:06 +02:00

60 lines
1.9 KiB
Vue

<script setup lang="ts">
import { CheckboxIndicator, CheckboxRoot } from 'reka-ui';
import { computed } from 'vue';
const props = defineProps<{
/**
* When set, the checkbox toggles this value inside an array model, which is
* how the permission matrix binds a column of boxes to one role.
* Without it the model is a plain boolean.
*/
value?: string | number;
invalid?: boolean;
disabled?: boolean;
id?: string;
}>();
const model = defineModel<boolean | Array<string | number> | null>();
const checked = computed(() => {
if (props.value === undefined) {
return Boolean(model.value);
}
return Array.isArray(model.value) && model.value.includes(props.value);
});
function toggle(state: boolean | 'indeterminate'): void {
if (props.value === undefined) {
model.value = state === true;
return;
}
const current = Array.isArray(model.value) ? model.value : [];
model.value = state === true
? [...current, props.value]
: current.filter((entry) => entry !== props.value);
}
</script>
<template>
<CheckboxRoot
:id="id"
:model-value="checked"
:disabled="disabled"
:aria-invalid="invalid || undefined"
class="flex size-5 shrink-0 cursor-pointer items-center justify-center rounded border transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-60"
:class="[
checked ? 'border-primary-600 bg-primary-600 text-white' : 'bg-white',
invalid ? 'border-red-500 focus-visible:outline-red-500' : 'border-slate-300 focus-visible:outline-primary-600',
]"
@update:model-value="toggle"
>
<CheckboxIndicator>
<i class="fas fa-check text-[0.65rem]" aria-hidden="true" />
</CheckboxIndicator>
</CheckboxRoot>
</template>