winbox-ui-next
Version:
We Design Vue 2.0: A Vue.js 3 UI Library
234 lines (233 loc) • 6.59 kB
JavaScript
import { defineComponent, ref, computed, toRefs, createVNode, mergeProps, isVNode } from "vue";
import Input from "../input/index.js";
import Trigger from "../trigger/index.js";
import { getPrefixCls } from "../_utils/global-config.js";
import { useOptions } from "../_hooks/use-options.js";
import { isFunction } from "../_utils/is.js";
import DropdownPanel from "../_components/dropdown/dropdown-panel.js";
import DropDownOption from "../_components/dropdown/dropdown-option.js";
import "../_components/dropdown/dropdown-optgroup.js";
import { getKeyDownHandler, CODE } from "../_utils/keyboard.js";
function _isSlot(s) {
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
}
var _AutoComplete = defineComponent({
name: "AutoComplete",
inheritAttrs: false,
props: {
modelValue: {
type: String,
default: void 0
},
defaultValue: {
type: String,
default: ""
},
disabled: {
type: Boolean,
default: false
},
data: {
type: Array,
default: () => []
},
popupContainer: {
type: [String, Object]
},
strict: {
type: Boolean,
default: false
},
filterOption: {
type: [Boolean, Function],
default: true
},
triggerProps: {
type: Object
},
onChange: {
type: [Function, Array]
},
onSearch: {
type: [Function, Array]
},
onSelect: {
type: [Function, Array]
}
},
emits: [
"update:modelValue",
"change",
"search",
"select"
],
setup(props, {
emit,
attrs,
slots
}) {
const prefixCls = getPrefixCls("auto-complete");
const _value = ref(props.defaultValue);
const inputRef = ref();
const computedValue = computed(() => {
var _a;
return (_a = props.modelValue) != null ? _a : _value.value;
});
const {
data
} = toRefs(props);
const dropdownRef = ref();
const optionRefs = ref({});
const strictFilterOption = (inputValue, optionInfo) => {
return optionInfo.label.includes(inputValue);
};
const mergedFilterOption = computed(() => {
if (isFunction(props.filterOption)) {
return props.filterOption;
}
if (props.filterOption && props.strict) {
return strictFilterOption;
}
return props.filterOption;
});
const extraOptions = ref([]);
const {
nodes,
optionInfoMap,
activeOption,
getNextActiveOption,
scrollIntoView
} = useOptions({
options: data,
extraOptions,
inputValue: computedValue,
filterOption: mergedFilterOption,
dropdownRef,
optionRefs
});
const handleChange = (value) => {
_value.value = value;
emit("update:modelValue", value);
emit("change", value);
};
const _popupVisible = ref(false);
const computedPopupVisible = computed(() => _popupVisible.value && nodes.value.length > 0);
const handlePopupVisibleChange = (popupVisible) => {
_popupVisible.value = popupVisible;
};
const handleSelect = (value, e) => {
var _a;
emit("select", value);
handleChange(value);
(_a = inputRef.value) == null ? void 0 : _a.blur();
};
const handleMouseEnter = (value, e) => {
const optionInfo = optionInfoMap.get(value);
if (optionInfo) {
activeOption.value = optionInfo;
}
};
const handleMouseLeave = (e) => {
activeOption.value = void 0;
};
const handleInputValueChange = (value) => {
emit("search", value);
handleChange(value);
};
const handleKeyDown = getKeyDownHandler(new Map([[CODE.ENTER, (e) => {
if (computedPopupVisible.value) {
if (activeOption.value) {
handleSelect(String(activeOption.value.value));
}
e.preventDefault();
}
}], [CODE.ESC, (e) => {
handlePopupVisibleChange(false);
e.preventDefault();
}], [CODE.ARROW_DOWN, (e) => {
if (computedPopupVisible.value) {
const next = getNextActiveOption("down");
if (next) {
activeOption.value = next;
scrollIntoView(next.value);
}
e.preventDefault();
}
}], [CODE.ARROW_UP, (e) => {
if (computedPopupVisible.value) {
const next = getNextActiveOption("up");
if (next) {
activeOption.value = next;
scrollIntoView(next.value);
}
e.preventDefault();
}
}]]));
const getOptionContentFunc = (item) => {
if (isFunction(slots.option) && item.value) {
const optionInfo = optionInfoMap.get(item.value);
const optionSlot = slots.option;
return () => optionSlot({
data: optionInfo
});
}
return () => item.label;
};
const renderOption = (item) => {
const {
value = ""
} = item;
return createVNode(DropDownOption, {
"ref": (ref2) => {
if (ref2 == null ? void 0 : ref2.$el) {
optionRefs.value[value] = ref2.$el;
}
},
"key": item.key,
"value": value,
"disabled": item.disabled,
"isActive": activeOption.value && value === activeOption.value.value,
"onClick": handleSelect,
"onMouseenter": handleMouseEnter,
"onMouseleave": handleMouseLeave
}, {
default: getOptionContentFunc(item)
});
};
const renderDropdown = () => {
const _children = nodes.value.map((node) => renderOption(node));
if (_children.length === 0) {
return null;
}
return createVNode(DropdownPanel, {
"ref": dropdownRef,
"class": `${prefixCls}-dropdown`
}, _isSlot(_children) ? _children : {
default: () => [_children]
});
};
return () => createVNode(Trigger, mergeProps({
"trigger": "focus",
"position": "bl",
"popupVisible": computedPopupVisible.value,
"clickToClose": false,
"preventFocus": true,
"popupOffset": 4,
"disabled": props.disabled,
"autoFitPopupWidth": true
}, props.triggerProps, {
"onPopupVisibleChange": handlePopupVisibleChange
}), {
default: () => [createVNode(Input, mergeProps({
"ref": inputRef,
"modelValue": computedValue.value,
"onInput": handleInputValueChange,
"disabled": props.disabled
}, attrs, {
"onKeydown": handleKeyDown
}), slots)],
content: renderDropdown
});
}
});
export { _AutoComplete as default };