UNPKG

song-ui-u

Version:

vue3 + js的PC前端组件库

285 lines (282 loc) 9.11 kB
import { defineComponent, ref, computed, watch, provide, createVNode, createTextVNode, nextTick } from 'vue'; import { useNamespace } from '../../../hook/use-namespace/index.mjs'; import { X, ChevronDown } from 'song-ui-pro-icon'; import '../../../hook/use-zindex/index.mjs'; import { SELECT_KEY } from './constant.mjs'; import '../../button/index.mjs'; import '../../buttonGroup/index.mjs'; import { XIcon } from '../../icon/index.mjs'; import '../../input/index.mjs'; import '../../textarea/index.mjs'; import '../../row/index.mjs'; import '../../col/index.mjs'; import '../../container/index.mjs'; import '../../checkbox/index.mjs'; import '../../switch/index.mjs'; import '../../form/index.mjs'; import '../../message/index.mjs'; import '../../mask/src/mask.mjs'; import '../../modal/index.mjs'; import '../../messageBox/index.mjs'; import '../../drawer/index.mjs'; import '../../badge/index.mjs'; import '../../space/index.mjs'; import '../../image/index.mjs'; import '../../radio/index.mjs'; import '../../divider/index.mjs'; import '../../chat/index.mjs'; import '../../progress/index.mjs'; import '../../upload/index.mjs'; import '../../vTree/index.mjs'; import '../../table/index.mjs'; import '../../tabs/index.mjs'; import '../../menu/index.mjs'; import '../../steps/index.mjs'; import '../../header/index.mjs'; import '../../breadcrumble/index.mjs'; import '../../datePicker/index.mjs'; import '../../tooltip/index.mjs'; import '../../popover/index.mjs'; import '../../timePicker/index.mjs'; import '../index.mjs'; import '../../collapse/index.mjs'; import '../../card/index.mjs'; import '../../timeline/index.mjs'; import '../../tag/index.mjs'; import '../../result/index.mjs'; import '../../sender/index.mjs'; var Select = /* @__PURE__ */ defineComponent({ name: "x-select", props: { modelValue: { type: [String, Number, Array], default: "" }, multiple: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, clearable: { type: Boolean, default: false }, placeholder: { type: String, default: "\u8BF7\u9009\u62E9" }, filterable: { type: Boolean, default: false }, size: { type: String, default: "default" }, width: { type: String, default: "100%" } }, emits: ["update:modelValue", "change", "clear", "blur", "focus"], setup(props, { slots, emit }) { const ns = useNamespace("select"); const visible = ref(false); const selectedLabel = ref(""); const selectedLabels = ref([]); const inputValue = ref(""); const options = ref([]); const selectRef = ref(null); const inputRef = ref(null); const dropdownRef = ref(null); const isFocus = ref(false); const isHover = ref(false); const styleWidth = computed(() => ({ width: props.width })); const controlSize = computed(() => props.size); const registerOption = (option) => { options.value.push(option); }; const unregisterOption = (id) => { const index = options.value.findIndex((option) => option.id === id); if (index !== -1) { options.value.splice(index, 1); } }; const selectOption = (value, label) => { if (props.multiple) { const values = Array.isArray(props.modelValue) ? [...props.modelValue] : []; const index = values.indexOf(value); if (index === -1) { values.push(value); selectedLabels.value.push(label); } else { values.splice(index, 1); selectedLabels.value.splice(index, 1); } emit("update:modelValue", values); emit("change", values); } else { if (selectedLabel.value == label) { selectedLabel.value = ""; } else { selectedLabel.value = label; } emit("update:modelValue", value); emit("change", value); closeDropdown(); } }; const clearSelection = (e) => { e.stopPropagation(); console.log("clearSelection"); if (props.multiple) { emit("update:modelValue", []); selectedLabels.value = []; } else { emit("update:modelValue", ""); selectedLabel.value = ""; } emit("clear"); }; const toggleDropdown = () => { if (props.disabled) return; visible.value = !visible.value; if (visible.value && props.filterable) { nextTick(() => { inputRef.value?.focus(); }); } }; const closeDropdown = () => { visible.value = false; if (props.filterable) { inputValue.value = ""; } }; const handleInput = (e) => { inputValue.value = e.target.value; }; const handleFocus = () => { isFocus.value = true; emit("focus"); }; const handleBlur = () => { isFocus.value = false; emit("blur"); }; const handleMouseEnter = () => { isHover.value = true; }; const handleMouseLeave = () => { isHover.value = false; }; const isOptionSelected = (value) => { if (props.multiple) { return Array.isArray(props.modelValue) && props.modelValue.includes(value); } return props.modelValue === value && selectedLabel.value; }; watch(() => props.modelValue, (newVal) => { if (props.multiple) ; else { const selectedOption = options.value.find((option) => option.value === newVal); selectedLabel.value = selectedOption ? selectedOption.label : ""; } }, { immediate: true }); provide(SELECT_KEY, { props, registerOption, unregisterOption, selectOption, isOptionSelected, inputValue }); const handleClickOutside = (e) => { if (selectRef.value && !selectRef.value.contains(e.target)) { closeDropdown(); } }; watch(visible, (newVal) => { if (newVal) { document.addEventListener("click", handleClickOutside); } else { document.removeEventListener("click", handleClickOutside); } }); return () => createVNode("div", { "ref": selectRef, "style": styleWidth.value, "class": [ns.b(), ns.is("focus", isFocus.value), ns.is("disabled", props.disabled), ns.m("size", controlSize.value), ns.is("clearable", props.clearable && !props.disabled && (props.multiple ? selectedLabels.value.length > 0 : selectedLabel.value)), ns.is("multiple", props.multiple), ns.is("filterable", props.filterable)], "onClick": toggleDropdown, "onMouseenter": handleMouseEnter, "onMouseleave": handleMouseLeave }, [createVNode("div", { "class": [ns.e("wrapper"), ns.is("hover", isHover.value && !props.disabled)] }, [props.multiple ? createVNode("div", { "class": [ns.e("tags")] }, [selectedLabels.value.length > 0 ? selectedLabels.value.map((label, index) => createVNode("span", { "class": [ns.e("tag")], "key": index }, [label, createVNode(XIcon, { "onClick": (e) => { e.stopPropagation(); selectOption(props.modelValue[index], label); } }, { default: () => [createVNode(X, null, null)] })])) : createVNode("span", { "class": [ns.e("placeholder")] }, null), props.filterable && createVNode("input", { "ref": inputRef, "type": "text", "class": [ns.e("filter-input")], "value": inputValue.value, "onInput": handleInput, "disabled": props.disabled, "onFocus": handleFocus, "onBlur": handleBlur, "placeholder": selectedLabel.value || props.placeholder }, null)]) : ( /* 单选模式 */ createVNode("div", { "class": [ns.e("selected")] }, [props.filterable && visible.value ? createVNode("input", { "ref": inputRef, "type": "text", "class": [ns.e("filter-input")], "value": inputValue.value, "placeholder": selectedLabel.value || props.placeholder, "onInput": handleInput, "onFocus": handleFocus, "onBlur": handleBlur }, null) : createVNode("span", { "class": [selectedLabel.value ? ns.e("label") : ns.e("placeholder")] }, [selectedLabel.value || props.placeholder])]) ), props.clearable && !props.disabled && (props.multiple ? selectedLabels.value.length > 0 : selectedLabel.value) && isHover.value && createVNode(XIcon, { "class": [ns.e("clear")], "onClick": clearSelection }, { default: () => [createVNode(X, null, null)] }), createVNode(XIcon, { "class": [ns.e("arrow"), visible.value ? ns.is("reverse", true) : ""] }, { default: () => [createVNode(ChevronDown, null, null)] })]), visible.value && createVNode("div", { "ref": dropdownRef, "class": [ns.e("dropdown")] }, [options.value.length === 0 && createVNode("div", { "class": [ns.e("empty")] }, [createTextVNode("\u65E0\u6570\u636E")]), slots.default?.()])]); } }); export { Select as default }; //# sourceMappingURL=select.mjs.map