prefixaut/splitterino

View on GitHub
src/components/checkbox.vue

Summary

Maintainability
Test Coverage
<template>
    <div class="checkbox" :class="{checked: internalValue}">
        <input
            type="checkbox"
            :id="'spl-checkbox-' + _uid"
            :value="internalValue"
            @change="inputChange($event)"
        />
        <label
            tabindex="0"
            :for="'spl-checkbox-' + _uid"
            @keypress="labelKeyPress($event)"
        >{{ label }}</label>
    </div>
</template>

<script lang="ts">
import { Vue, Component, Model, Prop, Watch } from 'vue-property-decorator';

import { convertToBoolean } from '../utils/converters';

@Component({ name: 'spl-checkbox' })
export default class CheckboxComponent extends Vue {
    @Model('change')
    public value: boolean;

    @Prop(String)
    public label: string;

    public internalValue: boolean = false;

    public inputChange(event) {
        this.internalValue = convertToBoolean(event.target.checked);
        this.$emit('change', this.internalValue);
    }

    public labelKeyPress(event: KeyboardEvent) {
        switch (event.key) {
            case ' ':
            case 'Enter':
                this.internalValue = !this.internalValue;
                event.preventDefault();
                event.stopPropagation();
                this.$emit('change', this.internalValue);
        }
    }

    @Watch('value', { immediate: true })
    onValueChange(newValue) {
        this.internalValue = convertToBoolean(newValue);
    }
}
</script>

<style lang="scss" scoped>
@import '../styles/core.scss';

.checkbox {
    position: relative;
    min-width: 35px;
    padding: 0 8px;
    display: inline-block;

    > input {
        appearance: none;
        display: none;
    }

    label {
        text-align: center;
        display: block;
        padding-top: 17px;
        cursor: pointer;

        &::before {
            content: '';
            position: absolute;
            border: 1px solid $spl-color-off-black;
            background: $spl-color-off-black;
            color: $spl-color-off-white;
            padding: 7px 7px;
            transition: 200ms;
            top: 0;
            left: 50%;
            margin-left: -8px;
        }

        &:focus {
            outline: none;

            &::before {
                border: 1px solid $spl-color-primary;
            }
        }
    }

    &.checked {
        label::before {
            background: $spl-color-primary;
        }
    }
}
</style>