All files / lib/components form-radio.vue

42.31% Statements 11/26
21.43% Branches 9/42
70% Functions 7/10
42.31% Lines 11/26
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 13618x 18x 18x   18x 18x                     18x     18x     2x                                                                                         2x           2x     2x                                                                                                                      
<template>
    <div :id="id || null"
    I     :class="buttons ? btnGroupClasses : radioGroupClasses"
         role="radiogroup"
         :dEata-toggle="buttons ? 'buttons' : null"
         :aria-required="required ? 'true' : null"
         :aria-invalid="invalid ? 'true' : null"
         @focusin.native="handleFocus"
         @focusout.native="handleFocus"
    >
        <label v-for="(option, idx) in formOptions"
               :class="buttons ? btnLabelClasses(option, idx) : labelClasses"
               :key="idx"
               :aria-pressed="buttons ? (option.value === localValue ? 'true' : 'false') : null"
        >
            <input :id="id ? (id + '__BV_radio_' + idx) : null"
                   :class="(custom && !buttons) ? 'custom-control-input' : null"
                   ref="inputs"
                   type="radio"
                   autocomplete="off"
                   v-model="localValue"
                   :value="option.value"
                   :name="name"
                   :required="name && required"
                   :disabled="option.disabled || disabled"
                   @change="$emit('change', returnObject ? option : option.value)"
            >
            <span v-if="custom && !buttons" class="custom-control-indicator" aria-hidden="true"></span>
            <span :class="(custom && !buttons) ? 'custom-control-description' : null" v-html="option.text"></span>
        </label>
    </div>
</template>
 
<script>
    import { formOptionsMixin, formMixin, formCustomMixin, formCheckBoxMixin } from '../mixins';
 
    export default {
        mixins: [formMixin, formCustomMixin, formCheckBoxMixin, formOptionsMixin],
        data() {
            return {
                localValue: this.value
            };
        },
        props: {
            value: {},
            options: {
                type: [Array, Object],
                default: null,
                required: true
            },
            size: {
                type: String,
                default: null
            },
            state: {
                type: String,
                default: null
            },
            invalid: {
                type: [Boolean, String],
                default: false
            },
            stacked: {
                type: Boolean,
                default: false
            },
            buttons: {
                // Render as button style
                type: Boolean,
                default: false
            },
            buttonVariant: {
                // Only applicable when rendered with button style
                type: String,
                default: 'secondary'
            },
            returnObject: {
                type: Boolean,
                default: false
            }
        },
        computed: {
            radioGroupClasses() {
                return [
                    this.size ? `form-control-${this.size}` : null,
                    this.state ? `has-${this.state}` : '',
                    this.stacked ? 'custom-controls-stacked' : ''
               ];
            },
            btnGroupClasses() {
                return [
                    'btn-group',
                    this.size ? `btn-group-${this.size}` : null,
                    this.stacked ? 'btn-group-vertical' : ''
                 ];
            },
            labelClasses() {
                return [
                    this.checkboxClass,
                    this.custom ? 'custom-radio' : null
                ];
            },
            inline() {
                return !this.stacked;
            }
        },
        methods: {
            btnLabelClasses(option, idx) {
                return [
                    'btn',
                    `btn-${this.buttonVariant}`,
                    (option.disabled || this.disabled) ? 'disabled' : '',
                    option.value === this.localValue ? 'active' : null,
                    // Fix staking issue (remove space between buttons)
                    (this.stacked && idx === this.formOptions.length - 1) ? '' : 'mb-0'
                ];
            },
            handleFocus(evt) {
                // When in buttons mode, we need to add 'focus' class to label when radio focused
                const el = evt.target;
                if (this.buttons && el && el.tagName === 'INPUT' && el.parentElement) {
                    const label = el.parentElement;
                    if (!label || label.tagName !== 'LABEL') {
                        return;
                    }
                    if (evt.type ==='focusin') {
                        label.classList.add('focus');
                    } else if (evt.type ==='focusout') {
                        label.classList.remove('focus');
                    }
                }
            }
        }
    };
</script>