UNPKG

bootstrap-vue

Version:

With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens

277 lines (273 loc) 7.97 kB
import looseEqual from '../utils/loose-equal' import { attemptBlur, attemptFocus } from '../utils/dom' import attrsMixin from './attrs' import normalizeSlotMixin from './normalize-slot' // @vue/component export default { mixins: [attrsMixin, normalizeSlotMixin], inheritAttrs: false, model: { prop: 'checked', event: 'input' }, props: { value: { // Value when checked // type: Object, // default: undefined }, checked: { // This is the v-model // type: Object, // default: undefined }, inline: { type: Boolean, default: false }, plain: { type: Boolean, default: false }, button: { // Only applicable in standalone mode (non group) type: Boolean, default: false }, buttonVariant: { // Only applicable when rendered with button style type: String // default: null }, ariaLabel: { // Placed on the input if present. type: String // default: null }, ariaLabelledby: { // Placed on the input if present. type: String // default: null } }, data() { return { localChecked: this.isGroup ? this.bvGroup.checked : this.checked, hasFocus: false } }, computed: { computedLocalChecked: { get() { return this.isGroup ? this.bvGroup.localChecked : this.localChecked }, set(val) { if (this.isGroup) { this.bvGroup.localChecked = val } else { this.localChecked = val } } }, isGroup() { // Is this check/radio a child of check-group or radio-group? return Boolean(this.bvGroup) }, isBtnMode() { // Support button style in single input mode return this.isGroup ? this.bvGroup.buttons : this.button }, isPlain() { return this.isBtnMode ? false : this.isGroup ? this.bvGroup.plain : this.plain }, isCustom() { return this.isBtnMode ? false : !this.isPlain }, isSwitch() { // Custom switch styling (checkboxes only) return this.isBtnMode || this.isRadio || this.isPlain ? false : this.isGroup ? this.bvGroup.switches : this.switch }, isInline() { return this.isGroup ? this.bvGroup.inline : this.inline }, isDisabled() { // Child can be disabled while parent isn't, but is always disabled if group is return this.isGroup ? this.bvGroup.disabled || this.disabled : this.disabled }, isRequired() { // Required only works when a name is provided for the input(s) // Child can only be required when parent is // Groups will always have a name (either user supplied or auto generated) return this.getName && (this.isGroup ? this.bvGroup.required : this.required) }, getName() { // Group name preferred over local name return (this.isGroup ? this.bvGroup.groupName : this.name) || null }, getForm() { return (this.isGroup ? this.bvGroup.form : this.form) || null }, getSize() { return (this.isGroup ? this.bvGroup.size : this.size) || '' }, getState() { return this.isGroup ? this.bvGroup.computedState : this.computedState }, getButtonVariant() { // Local variant preferred over group variant if (this.buttonVariant) { return this.buttonVariant } else if (this.isGroup && this.bvGroup.buttonVariant) { return this.bvGroup.buttonVariant } // default variant return 'secondary' }, buttonClasses() { // Same for radio & check return [ 'btn', `btn-${this.getButtonVariant}`, { [`btn-${this.getSize}`]: this.getSize, // 'disabled' class makes "button" look disabled disabled: this.isDisabled, // 'active' class makes "button" look pressed active: this.isChecked, // Focus class makes button look focused focus: this.hasFocus } ] }, computedAttrs() { return { ...this.bvAttrs, id: this.safeId(), type: this.isRadio ? 'radio' : 'checkbox', name: this.getName, form: this.getForm, disabled: this.isDisabled, required: this.isRequired, 'aria-required': this.isRequired || null, 'aria-label': this.ariaLabel || null, 'aria-labelledby': this.ariaLabelledby || null } } }, watch: { checked(newValue) { if (!looseEqual(newValue, this.computedLocalChecked)) { this.computedLocalChecked = newValue } } }, methods: { handleFocus(evt) { // When in buttons mode, we need to add 'focus' class to label when input focused // As it is the hidden input which has actual focus if (evt.target) { if (evt.type === 'focus') { this.hasFocus = true } else if (evt.type === 'blur') { this.hasFocus = false } } }, // Convenience methods for focusing the input focus() { if (!this.isDisabled) { attemptFocus(this.$refs.input) } }, blur() { if (!this.isDisabled) { attemptBlur(this.$refs.input) } } }, render(h) { const defaultSlot = this.normalizeSlot() // Generate the input element const on = { change: this.handleChange } if (this.isBtnMode) { // Handlers for focus styling when in button mode on.focus = on.blur = this.handleFocus } const input = h('input', { ref: 'input', key: 'input', on, class: { 'form-check-input': this.isPlain, 'custom-control-input': this.isCustom, 'is-valid': this.getState === true && !this.isBtnMode, 'is-invalid': this.getState === false && !this.isBtnMode, // https://github.com/bootstrap-vue/bootstrap-vue/issues/2911 'position-static': this.isPlain && !defaultSlot }, directives: [ { name: 'model', rawName: 'v-model', value: this.computedLocalChecked, expression: 'computedLocalChecked' } ], attrs: this.computedAttrs, domProps: { value: this.value, checked: this.isChecked } }) if (this.isBtnMode) { // Button mode let button = h('label', { class: this.buttonClasses }, [input, defaultSlot]) if (!this.isGroup) { // Standalone button mode, so wrap in 'btn-group-toggle' // and flag it as inline-block to mimic regular buttons button = h('div', { class: ['btn-group-toggle', 'd-inline-block'] }, [button]) } return button } else { // Not button mode let label = h() // If no label content in plain mode we dont render the label // https://github.com/bootstrap-vue/bootstrap-vue/issues/2911 if (!(this.isPlain && !defaultSlot)) { label = h( 'label', { class: { 'form-check-label': this.isPlain, 'custom-control-label': this.isCustom }, attrs: { for: this.safeId() } }, defaultSlot ) } // Wrap it in a div return h( 'div', { class: { 'form-check': this.isPlain, 'form-check-inline': this.isPlain && this.isInline, 'custom-control': this.isCustom, 'custom-control-inline': this.isCustom && this.isInline, 'custom-checkbox': this.isCustom && this.isCheck && !this.isSwitch, 'custom-switch': this.isSwitch, 'custom-radio': this.isCustom && this.isRadio, // Temporary until Bootstrap v4 supports sizing (most likely in V5) [`b-custom-control-${this.getSize}`]: Boolean(this.getSize && !this.isBtnMode) } }, [input, label] ) } } }