UNPKG

@gitlab/ui

Version:
144 lines (138 loc) 4.54 kB
import { extend } from '../../vue'; import { NAME_FORM_SELECT } from '../../constants/components'; import { EVENT_NAME_CHANGE } from '../../constants/events'; import { PROP_TYPE_BOOLEAN_STRING, PROP_TYPE_BOOLEAN, PROP_TYPE_NUMBER } from '../../constants/props'; import { SLOT_NAME_FIRST } from '../../constants/slots'; import { from } from '../../utils/array'; import { attemptFocus, attemptBlur } from '../../utils/dom'; import { htmlOrText } from '../../utils/html'; import { isArray } from '../../utils/inspect'; import { sortKeys } from '../../utils/object'; import { makePropsConfigurable, makeProp } from '../../utils/props'; import { props as props$3, formControlMixin } from '../../mixins/form-control'; import { props as props$4, formCustomMixin } from '../../mixins/form-custom'; import { props as props$5, formSizeMixin } from '../../mixins/form-size'; import { props as props$6, formStateMixin } from '../../mixins/form-state'; import { props as props$1, idMixin } from '../../mixins/id'; import { props as props$2, modelMixin, MODEL_PROP_NAME, MODEL_EVENT_NAME } from '../../mixins/model'; import { normalizeSlotMixin } from '../../mixins/normalize-slot'; import { optionsMixin } from './helpers/mixin-options'; import { BFormSelectOption } from './form-select-option'; import { BFormSelectOptionGroup } from './form-select-option-group'; // --- Props --- const props = makePropsConfigurable(sortKeys({ ...props$1, ...props$2, ...props$3, ...props$4, ...props$5, ...props$6, ariaInvalid: makeProp(PROP_TYPE_BOOLEAN_STRING, false), multiple: makeProp(PROP_TYPE_BOOLEAN, false), // Browsers default size to `0`, which shows 4 rows in most browsers in multiple mode // Size of `1` can bork out Firefox selectSize: makeProp(PROP_TYPE_NUMBER, 0) }), NAME_FORM_SELECT); // --- Main component --- // @vue/component const BFormSelect = /*#__PURE__*/extend({ name: NAME_FORM_SELECT, mixins: [idMixin, modelMixin, formControlMixin, formSizeMixin, formStateMixin, formCustomMixin, optionsMixin, normalizeSlotMixin], props, data() { return { localValue: this[MODEL_PROP_NAME] }; }, computed: { computedSelectSize() { // Custom selects with a size of zero causes the arrows to be hidden, // so dont render the size attribute in this case return !this.plain && this.selectSize === 0 ? null : this.selectSize; }, inputClass() { return [this.plain ? 'form-control' : 'custom-select', this.size && this.plain ? `form-control-${this.size}` : null, this.size && !this.plain ? `custom-select-${this.size}` : null, this.stateClass]; } }, watch: { value(newValue) { this.localValue = newValue; }, localValue() { this.$emit(MODEL_EVENT_NAME, this.localValue); } }, methods: { focus() { attemptFocus(this.$refs.input); }, blur() { attemptBlur(this.$refs.input); }, onChange(event) { const { target } = event; const selectedValue = from(target.options).filter(o => o.selected).map(o => '_value' in o ? o._value : o.value); this.localValue = target.multiple ? selectedValue : selectedValue[0]; this.$nextTick(() => { this.$emit(EVENT_NAME_CHANGE, this.localValue); }); } }, render(h) { const { name, disabled, required, computedSelectSize: size, localValue: value } = this; const $options = this.formOptions.map((option, index) => { const { value, label, options, disabled } = option; const key = `option_${index}`; return isArray(options) ? h(BFormSelectOptionGroup, { props: { label, options }, key }) : h(BFormSelectOption, { props: { value, disabled }, domProps: htmlOrText(option.html, option.text), key }); }); return h('select', { class: this.inputClass, attrs: { id: this.safeId(), name, form: this.form || null, multiple: this.multiple || null, size, disabled, required, 'aria-required': required ? 'true' : null, 'aria-invalid': this.computedAriaInvalid }, on: { change: this.onChange }, directives: [{ name: 'model', value }], ref: 'input' }, [this.normalizeSlot(SLOT_NAME_FIRST), $options, this.normalizeSlot()]); } }); export { BFormSelect, props };