UNPKG

@gitlab/ui

Version:
129 lines (121 loc) 4.19 kB
import { extend } from '../vue'; import { PROP_TYPE_BOOLEAN_STRING, PROP_TYPE_BOOLEAN } from '../constants/props'; import { SLOT_NAME_FIRST } from '../constants/slots'; import { htmlOrText } from '../utils/html'; import { looseEqual } from '../utils/loose-equal'; import { makeModelMixin } from '../utils/model'; import { sortKeys, pick, omit } from '../utils/object'; import { makePropsConfigurable, makeProp } from '../utils/props'; import { BFormCheckbox } from '../components/form-checkbox/form-checkbox'; import { BFormRadio } from '../components/form-radio/form-radio'; import { props as props$2, formControlMixin } from './form-control'; import { props as props$6, formCustomMixin } from './form-custom'; import { props as props$3, formOptionsMixin } from './form-options'; import { props as props$4, formSizeMixin } from './form-size'; import { props as props$5, formStateMixin } from './form-state'; import { props as props$1, idMixin } from './id'; import { normalizeSlotMixin } from './normalize-slot'; // --- Constants --- // Attributes to pass down to checks/radios instead of applying them to the group const PASS_DOWN_ATTRS = ['aria-describedby', 'aria-labelledby']; const { mixin: modelMixin, props: modelProps, prop: MODEL_PROP_NAME, event: MODEL_EVENT_NAME } = makeModelMixin('checked'); // --- Props --- const props = makePropsConfigurable(sortKeys({ ...props$1, ...modelProps, ...props$2, ...props$3, ...props$4, ...props$5, ...props$6, ariaInvalid: makeProp(PROP_TYPE_BOOLEAN_STRING, false), stacked: makeProp(PROP_TYPE_BOOLEAN, false), validated: makeProp(PROP_TYPE_BOOLEAN, false) }), 'formRadioCheckGroups'); // --- Mixin --- // @vue/component const formRadioCheckGroupMixin = extend({ mixins: [idMixin, modelMixin, normalizeSlotMixin, formControlMixin, formOptionsMixin, formSizeMixin, formStateMixin, formCustomMixin], inheritAttrs: false, props, data() { return { localChecked: this[MODEL_PROP_NAME] }; }, computed: { inline() { return !this.stacked; }, groupName() { // Checks/Radios tied to the same model must have the same name, // especially for ARIA accessibility return this.name || this.safeId(); }, groupClasses() { const { validated } = this; return { 'was-validated': validated }; } }, watch: { [MODEL_PROP_NAME](newValue) { if (!looseEqual(newValue, this.localChecked)) { this.localChecked = newValue; } }, localChecked(newValue, oldValue) { if (!looseEqual(newValue, oldValue)) { this.$emit(MODEL_EVENT_NAME, newValue); } } }, render(h) { const { isRadioGroup } = this; const attrs = pick(this.$attrs, PASS_DOWN_ATTRS); const optionComponent = isRadioGroup ? BFormRadio : BFormCheckbox; const $inputs = this.formOptions.map((option, index) => { const key = `BV_option_${index}`; return h(optionComponent, { props: { // Individual radios or checks can be disabled in a group disabled: option.disabled || false, id: this.safeId(key), value: option.value // We don't need to include these, since the input's will know they are inside here // form: this.form || null, // name: this.groupName, // required: Boolean(this.name && this.required), // state: this.state }, attrs, key }, [h('span', { domProps: htmlOrText(option.html, option.text) })]); }); return h('div', { class: [this.groupClasses, 'bv-no-focus-ring'], attrs: { ...omit(this.$attrs, PASS_DOWN_ATTRS), 'aria-invalid': this.computedAriaInvalid, 'aria-required': this.required ? 'true' : null, id: this.safeId(), role: isRadioGroup ? 'radiogroup' : 'group', // Add `tabindex="-1"` to allow group to be focused if needed by screen readers tabindex: '-1' } }, [this.normalizeSlot(SLOT_NAME_FIRST), $inputs, this.normalizeSlot()]); } }); export { MODEL_EVENT_NAME, MODEL_PROP_NAME, formRadioCheckGroupMixin, props };