Files
Kotyata/apps/client/components/radio-button.vue
2026-03-17 13:24:22 +03:00

107 lines
1.9 KiB
Vue

<template>
<div
:class="[
cn.b(),
cn.is('checked', checked),
cn.is('disabled', disabled),
cn.is('focused', focused),
cn.is('disabled', disabled),
]"
@click="handleChange"
>
<p :class="[cn.e('label')]">
<slot>
{{ label }}
</slot>
</p>
<p v-if="caption || $slots.caption" :class="[cn.e('caption')]">
<slot name="caption">
{{ caption }}
</slot>
</p>
</div>
</template>
<script setup lang="ts">
export interface Props {
id: string
value: string | number
label?: string
caption?: string
disabled?: boolean
modelValue?: string | number
required?: boolean
}
defineOptions({
name: 'RadioButton',
})
const props = withDefaults(defineProps<Props>(), {
disabled: false,
trueValue: true,
falseValue: false,
required: false,
modelValue: undefined,
})
const slots = useSlots()
const { checked, focused, handleChange } = useRadio(props, slots)
const cn = useClassname('radio-button')
</script>
<style lang="scss">
.radio-button {
$self: &;
@include txt-i-m;
--border-color: #{$clr-grey-300};
--border-width: 1px;
display: inline-flex;
justify-content: center;
align-items: center;
flex-direction: column;
text-align: center;
height: 48px;
padding: 8px 16px;
border-radius: 12px;
outline: var(--border-width) solid var(--border-color);
outline-offset: calc(var(--border-width) * -1);
cursor: pointer;
transition: .2s ease-out;
transition-property: outline-color, background-color, color;
user-select: none;
&:hover {
--border-color: transparent;
background-color: $clr-grey-200;
}
&.is-checked {
--border-color: transparent;
background-color: $clr-cyan-500;
color: $clr-white;
}
&.is-disabled {
opacity: 0.4;
pointer-events: none;
}
&__caption {
@include txt-r-m;
color: $clr-cyan-400;
#{$self}.is-checked & {
color: $clr-cyan-300;
}
}
}
</style>