buefy
Version:
Lightweight UI components for Vue.js based on Bulma
393 lines (342 loc) • 13.5 kB
JavaScript
import { _ as _defineProperty, a as _typeof } from './chunk-d6200087.js';
import { g as getValueByPath } from './chunk-e5fce48f.js';
import { F as FormElementMixin } from './chunk-591ee4a2.js';
import { _ as __vue_normalize__ } from './chunk-e8d90b72.js';
import { I as Input } from './chunk-b56eb2c8.js';
var script = {
name: 'BAutocomplete',
components: _defineProperty({}, Input.name, Input),
mixins: [FormElementMixin],
inheritAttrs: false,
props: {
value: [Number, String],
data: {
type: Array,
default: function _default() {
return [];
}
},
field: {
type: String,
default: 'value'
},
keepFirst: Boolean,
clearOnSelect: Boolean,
openOnFocus: Boolean,
customFormatter: Function
},
data: function data() {
return {
selected: null,
hovered: null,
isActive: false,
newValue: this.value,
newAutocomplete: this.autocomplete || 'off',
isListInViewportVertically: true,
hasFocus: false,
_isAutocomplete: true,
_elementRef: 'input'
};
},
computed: {
/**
* White-listed items to not close when clicked.
* Add input, dropdown and all children.
*/
whiteList: function whiteList() {
var whiteList = [];
whiteList.push(this.$refs.input.$el.querySelector('input'));
whiteList.push(this.$refs.dropdown); // Add all chidren from dropdown
if (this.$refs.dropdown !== undefined) {
var children = this.$refs.dropdown.querySelectorAll('*');
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var child = _step.value;
whiteList.push(child);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
return whiteList;
},
/**
* Check if exists default slot
*/
hasDefaultSlot: function hasDefaultSlot() {
return !!this.$scopedSlots.default;
},
/**
* Check if exists "empty" slot
*/
hasEmptySlot: function hasEmptySlot() {
return !!this.$slots.empty;
},
/**
* Check if exists "header" slot
*/
hasHeaderSlot: function hasHeaderSlot() {
return !!this.$slots.header;
},
/**
* Check if exists "footer" slot
*/
hasFooterSlot: function hasFooterSlot() {
return !!this.$slots.footer;
}
},
watch: {
/**
* When dropdown is toggled, check the visibility to know when
* to open upwards.
*/
isActive: function isActive(active) {
var _this = this;
if (active) {
this.calcDropdownInViewportVertical();
} else {
this.$nextTick(function () {
return _this.setHovered(null);
}); // Timeout to wait for the animation to finish before recalculating
setTimeout(function () {
_this.calcDropdownInViewportVertical();
}, 100);
}
},
/**
* When updating input's value
* 1. Emit changes
* 2. If value isn't the same as selected, set null
* 3. Close dropdown if value is clear or else open it
*/
newValue: function newValue(value) {
this.$emit('input', value); // Check if selected is invalid
var currentValue = this.getValue(this.selected);
if (currentValue && currentValue !== value) {
this.setSelected(null, false);
} // Close dropdown if input is clear or else open it
if (this.hasFocus && (!this.openOnFocus || value)) {
this.isActive = !!value;
}
},
/**
* When v-model is changed:
* 1. Update internal value.
* 2. If it's invalid, validate again.
*/
value: function value(_value) {
this.newValue = _value;
!this.isValid && this.$refs.input.checkHtml5Validity();
},
/**
* Select first option if "keep-first
*/
data: function data(value) {
// Keep first option always pre-selected
if (this.keepFirst) {
this.selectFirstOption(value);
}
}
},
methods: {
/**
* Set which option is currently hovered.
*/
setHovered: function setHovered(option) {
if (option === undefined) return;
this.hovered = option;
},
/**
* Set which option is currently selected, update v-model,
* update input value and close dropdown.
*/
setSelected: function setSelected(option) {
var _this2 = this;
var closeDropdown = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (option === undefined) return;
this.selected = option;
this.$emit('select', this.selected);
if (this.selected !== null) {
this.newValue = this.clearOnSelect ? '' : this.getValue(this.selected);
}
closeDropdown && this.$nextTick(function () {
_this2.isActive = false;
});
},
/**
* Select first option
*/
selectFirstOption: function selectFirstOption(options) {
var _this3 = this;
this.$nextTick(function () {
if (options.length) {
// If has visible data or open on focus, keep updating the hovered
if (_this3.openOnFocus || _this3.newValue !== '' && _this3.hovered !== options[0]) {
_this3.setHovered(options[0]);
}
} else {
_this3.setHovered(null);
}
});
},
/**
* Enter key listener.
* Select the hovered option.
*/
enterPressed: function enterPressed() {
if (this.hovered === null) return;
this.setSelected(this.hovered);
},
/**
* Tab key listener.
* Select hovered option if it exists, close dropdown, then allow
* native handling to move to next tabbable element.
*/
tabPressed: function tabPressed() {
if (this.hovered === null) {
this.isActive = false;
return;
}
this.setSelected(this.hovered);
},
/**
* Close dropdown if clicked outside.
*/
clickedOutside: function clickedOutside(event) {
if (this.whiteList.indexOf(event.target) < 0) this.isActive = false;
},
/**
* Return display text for the input.
* If object, get value from path, or else just the value.
*/
getValue: function getValue(option) {
if (!option) return;
if (typeof this.customFormatter !== 'undefined') {
return this.customFormatter(option);
}
return _typeof(option) === 'object' ? getValueByPath(option, this.field) : option;
},
/**
* Calculate if the dropdown is vertically visible when activated,
* otherwise it is openened upwards.
*/
calcDropdownInViewportVertical: function calcDropdownInViewportVertical() {
var _this4 = this;
this.$nextTick(function () {
/**
* this.$refs.dropdown may be undefined
* when Autocomplete is conditional rendered
*/
if (_this4.$refs.dropdown === undefined) return;
var rect = _this4.$refs.dropdown.getBoundingClientRect();
_this4.isListInViewportVertically = rect.top >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight);
});
},
/**
* Arrows keys listener.
* If dropdown is active, set hovered option, or else just open.
*/
keyArrows: function keyArrows(direction) {
var sum = direction === 'down' ? 1 : -1;
if (this.isActive) {
var index = this.data.indexOf(this.hovered) + sum;
index = index > this.data.length - 1 ? this.data.length : index;
index = index < 0 ? 0 : index;
this.setHovered(this.data[index]);
var list = this.$refs.dropdown.querySelector('.dropdown-content');
var element = list.querySelectorAll('a.dropdown-item:not(.is-disabled)')[index];
if (!element) return;
var visMin = list.scrollTop;
var visMax = list.scrollTop + list.clientHeight - element.clientHeight;
if (element.offsetTop < visMin) {
list.scrollTop = element.offsetTop;
} else if (element.offsetTop >= visMax) {
list.scrollTop = element.offsetTop - list.clientHeight + element.clientHeight;
}
} else {
this.isActive = true;
}
},
/**
* Focus listener.
* If value is the same as selected, select all text.
*/
focused: function focused(event) {
if (this.getValue(this.selected) === this.newValue) {
this.$el.querySelector('input').select();
}
if (this.openOnFocus) {
this.isActive = true;
if (this.keepFirst) {
this.selectFirstOption(this.data);
}
}
this.hasFocus = true;
this.$emit('focus', event);
},
/**
* Blur listener.
*/
onBlur: function onBlur(event) {
this.hasFocus = false;
this.$emit('blur', event);
},
onInput: function onInput(event) {
var currentValue = this.getValue(this.selected);
if (currentValue && currentValue === this.newValue) return;
this.$emit('typing', this.newValue);
}
},
created: function created() {
if (typeof window !== 'undefined') {
document.addEventListener('click', this.clickedOutside);
window.addEventListener('resize', this.calcDropdownInViewportVertical);
}
},
beforeDestroy: function beforeDestroy() {
if (typeof window !== 'undefined') {
document.removeEventListener('click', this.clickedOutside);
window.removeEventListener('resize', this.calcDropdownInViewportVertical);
}
}
};
/* script */
const __vue_script__ = script;
/* template */
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"autocomplete control",class:{'is-expanded': _vm.expanded}},[_c('b-input',_vm._b({ref:"input",attrs:{"type":"text","size":_vm.size,"loading":_vm.loading,"rounded":_vm.rounded,"icon":_vm.icon,"icon-pack":_vm.iconPack,"maxlength":_vm.maxlength,"autocomplete":_vm.newAutocomplete,"use-html5-validation":_vm.useHtml5Validation},on:{"input":_vm.onInput,"focus":_vm.focused,"blur":_vm.onBlur},nativeOn:{"keyup":function($event){if(!('button' in $event)&&_vm._k($event.keyCode,"esc",27,$event.key)){ return null; }$event.preventDefault();_vm.isActive = false;},"keydown":[function($event){if(!('button' in $event)&&_vm._k($event.keyCode,"tab",9,$event.key)){ return null; }_vm.tabPressed($event);},function($event){if(!('button' in $event)&&_vm._k($event.keyCode,"enter",13,$event.key)){ return null; }$event.preventDefault();_vm.enterPressed($event);},function($event){if(!('button' in $event)&&_vm._k($event.keyCode,"up",38,$event.key)){ return null; }$event.preventDefault();_vm.keyArrows('up');},function($event){if(!('button' in $event)&&_vm._k($event.keyCode,"down",40,$event.key)){ return null; }$event.preventDefault();_vm.keyArrows('down');}]},model:{value:(_vm.newValue),callback:function ($$v) {_vm.newValue=$$v;},expression:"newValue"}},'b-input',_vm.$attrs,false)),_vm._v(" "),_c('transition',{attrs:{"name":"fade"}},[_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.isActive && (_vm.data.length > 0 || _vm.hasEmptySlot || _vm.hasHeaderSlot)),expression:"isActive && (data.length > 0 || hasEmptySlot || hasHeaderSlot)"}],ref:"dropdown",staticClass:"dropdown-menu",class:{ 'is-opened-top': !_vm.isListInViewportVertically }},[_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.isActive),expression:"isActive"}],staticClass:"dropdown-content"},[(_vm.hasHeaderSlot)?_c('div',{staticClass:"dropdown-item"},[_vm._t("header")],2):_vm._e(),_vm._v(" "),_vm._l((_vm.data),function(option,index){return _c('a',{key:index,staticClass:"dropdown-item",class:{ 'is-hovered': option === _vm.hovered },on:{"click":function($event){_vm.setSelected(option);}}},[(_vm.hasDefaultSlot)?_vm._t("default",null,{option:option,index:index}):_c('span',[_vm._v("\n "+_vm._s(_vm.getValue(option, true))+"\n ")])],2)}),_vm._v(" "),(_vm.data.length === 0 && _vm.hasEmptySlot)?_c('div',{staticClass:"dropdown-item is-disabled"},[_vm._t("empty")],2):_vm._e(),_vm._v(" "),(_vm.hasFooterSlot)?_c('div',{staticClass:"dropdown-item"},[_vm._t("footer")],2):_vm._e()],2)])])],1)};
var __vue_staticRenderFns__ = [];
/* style */
const __vue_inject_styles__ = undefined;
/* scoped */
const __vue_scope_id__ = undefined;
/* module identifier */
const __vue_module_identifier__ = undefined;
/* functional template */
const __vue_is_functional_template__ = false;
/* style inject */
/* style inject SSR */
var Autocomplete = __vue_normalize__(
{ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
__vue_inject_styles__,
__vue_script__,
__vue_scope_id__,
__vue_is_functional_template__,
__vue_module_identifier__,
undefined,
undefined
);
export { Autocomplete as A };