UNPKG

@gitlab/ui

Version:
154 lines (147 loc) 4.54 kB
import { extend } from '../../vue'; import { NAME_FORM_SELECT } from '../../constants/components'; import { EVENT_NAME_CHANGE, EVENT_NAME_INPUT } from '../../constants/events'; 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 { props as props$2, formControlMixin } from '../../mixins/form-control'; import { props as props$3, formCustomMixin } from '../../mixins/form-custom'; import { props as props$4, formSizeMixin } from '../../mixins/form-size'; import { props as props$5, formStateMixin } from '../../mixins/form-state'; import { normalizeSlotMixin } from '../../mixins/normalize-slot'; import { props as props$1, idMixin } from '../../mixins/id'; import { optionsMixin } from './helpers/mixin-options'; import { BFormSelectOption } from './form-select-option'; import { BFormSelectOptionGroup } from './form-select-option-group'; const MODEL_PROP_NAME = 'value'; const MODEL_EVENT_NAME = EVENT_NAME_INPUT; // --- Props --- const props = sortKeys({ ...props$1, [MODEL_PROP_NAME]: {}, ...props$2, ...props$3, ...props$4, ...props$5, ariaInvalid: { type: [Boolean, String], required: false, default: false }, multiple: { type: Boolean, required: false, default: false }, // Browsers default size to `0`, which shows 4 rows in most browsers in multiple mode // Size of `1` can bork out Firefox selectSize: { type: Number, required: false, default: 0 } }); // --- Main component --- // @vue/component const BFormSelect = /*#__PURE__*/extend({ name: NAME_FORM_SELECT, mixins: [idMixin, formControlMixin, formSizeMixin, formStateMixin, formCustomMixin, optionsMixin, normalizeSlotMixin], model: { prop: MODEL_PROP_NAME, event: MODEL_EVENT_NAME }, 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.target; 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 = this.name, disabled = this.disabled, required = this.required, size = this.computedSelectSize, value = this.localValue; const $options = this.formOptions.map((option, index) => { const value = option.value, label = option.label, options = option.options, disabled = option.disabled; 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 };