-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathCheckbox.vue
106 lines (96 loc) · 2.28 KB
/
Checkbox.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<template>
<div
class="group inline-flex cursor-pointer flex-nowrap items-center justify-center transition hover:text-secondaryDark"
role="checkbox"
:aria-checked="on"
>
<input
:id="checkboxID"
type="checkbox"
:name="name"
class="checkbox"
:checked="on"
@change="emit('change')"
/>
<label
:for="checkboxID"
class="cursor-pointer truncate pl-0 align-middle font-semibold"
>
<slot></slot>
</label>
</div>
</template>
<script lang="ts">
/*
This checkboxIDCounter is tracked in the global scope in order to ensure that each checkbox has a unique ID.
When we use this component multiple times on the same page, we need to ensure that each checkbox has a unique ID.
This is because the label's for attribute needs to match the checkbox's id attribute.
That's why we use a global counter that increments each time we use this component.
*/
let checkboxIDCounter = 564275
</script>
<script setup lang="ts">
// Unique ID for checkbox
const checkboxID = `checkbox-${checkboxIDCounter++}`
withDefaults(
defineProps<{
on: boolean
name: string
}>(),
{
on: false,
name: "checkbox",
},
)
const emit = defineEmits<{
(e: "change"): void
}>()
</script>
<style lang="scss" scoped>
.checkbox[type="checkbox"] {
@apply relative;
@apply appearance-none;
@apply hidden;
& + label {
@apply inline-flex items-center justify-center;
@apply cursor-pointer;
@apply relative;
&::before {
@apply border-2 border-divider;
@apply rounded;
@apply group-hover:border-accentDark;
@apply inline-flex;
@apply items-center;
@apply justify-center;
@apply text-transparent;
@apply h-4;
@apply w-4;
@apply mr-2;
@apply transition;
@apply empty:mr-0;
content: "";
}
&::after {
content: "";
border: solid;
border-width: 0 1.9px 1.9px 0;
height: 0.6rem;
width: 0.3rem;
left: 0.35rem;
position: absolute;
top: 2px;
transform: rotate(45deg);
opacity: 0;
}
}
&:checked + label::before {
@apply bg-accent;
@apply border-accent;
@apply text-accentContrast;
}
&:checked + label::after {
@apply text-accentContrast;
opacity: 1;
}
}
</style>