braindrops.nicwands.com/shared/Checkbox.vue
2026-08-11 10:24:27 -04:00

95 lines
2.2 KiB
Vue

<template>
<label class="shared-checkbox" :class="{ 'is-checked': model, 'is-disabled': disabled }">
<input
type="checkbox"
:disabled="disabled"
v-model="model"
/>
<span class="box">
<svg class="check" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 4L3.5 6.5L9 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
<span v-if="$slots.default" class="checkbox-label"><slot /></span>
</label>
</template>
<script setup>
const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
})
const model = defineModel()
</script>
<style lang="scss">
.shared-checkbox {
--t-duration: 200ms;
--t-ease: var(--ease-out-quad);
display: inline-flex;
align-items: center;
gap: rs(10px);
cursor: pointer;
user-select: none;
input[type='checkbox'] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
pointer-events: none;
}
.box {
flex-shrink: 0;
width: rs(18px);
height: rs(18px);
border: rs(1px) solid var(--grey-400);
border-radius: rs(4px);
display: flex;
align-items: center;
justify-content: center;
background: transparent;
transition:
background var(--t-duration) var(--t-ease),
border-color var(--t-duration) var(--t-ease);
.check {
width: rs(10px);
height: auto;
color: var(--ivory);
opacity: 0;
transform: scale(0.5);
transition:
opacity var(--t-duration) var(--t-ease),
transform var(--t-duration) var(--t-ease);
}
}
.checkbox-label {
@include p;
}
&:hover .box {
border-color: var(--theme-contrast);
}
&.is-checked .box {
background: var(--theme-contrast);
border-color: var(--theme-contrast);
.check {
opacity: 1;
transform: none;
}
}
&.is-disabled {
opacity: 0.3;
pointer-events: none;
}
}
</style>