UNPKG

@opensig/opendesign

Version:

608 lines (607 loc) 23 kB
import { defineComponent, ref, computed, inject, watch, provide, nextTick, createBlock, openBlock, unref, mergeProps, withCtx, createVNode, createElementBlock, createElementVNode, createCommentVNode, Fragment, renderList, toDisplayString, normalizeClass, renderSlot, createTextVNode, normalizeStyle, Teleport, withDirectives, vShow } from "vue"; import { IconClose, IconLoading, IconChevronDown } from "../_utils/icons.mjs"; import { OPopup } from "../popup/index.mjs"; import { OPopover } from "../popover/index.mjs"; import { OScroller } from "../scrollbar/index.mjs"; import ClientOnly from "../_components/client-only.mjs"; import _sfc_main$1 from "../_components/in-box/InBox.vue.mjs"; import _sfc_main$2 from "./OCascaderV2Panel.vue.mjs"; import { isUndefined, isArrayEqual, isFunction, isArray } from "../_utils/is.mjs"; import { formItemInjectKey } from "../form/provide.mjs"; import { cascaderV2InjectKey } from "./provide.mjs"; import { cascaderV2Props } from "./types.mjs"; const _hoisted_1 = ["disabled", "value", "placeholder", "readonly"]; const _hoisted_2 = { key: 1, class: "o-cascader-v2-tags-wrap" }; const _hoisted_3 = { class: "o-cascader-v2-tag-text" }; const _hoisted_4 = ["onClick"]; const _hoisted_5 = { class: "o-cascader-v2-tags" }; const _hoisted_6 = { class: "o-cascader-v2-tag-text" }; const _hoisted_7 = ["onClick"]; const _hoisted_8 = ["value", "readonly", "disabled"]; const _hoisted_9 = { class: "o-cascader-v2-suffix" }; const _hoisted_10 = { class: "o-cascader-v2-suffix-icon" }; const _hoisted_11 = { key: 0, class: "o-cascader-v2-loading" }; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "OCascaderV2", props: cascaderV2Props, emits: ["update:modelValue", "change", "options-visible-change", "clear", "lazyload-error"], setup(__props, { emit: __emit }) { const props = __props; const emits = __emit; const cascaderV2Ref = ref(); const cascaderV2El = computed(() => { var _a; return (_a = cascaderV2Ref.value) == null ? void 0 : _a.$el; }); const cascaderv2Panel = ref(); const inputRef = ref(); const inputMirrorRef = ref(); const inputWidth = ref(12); const isSelecting = ref(false); const lazyRootLoading = ref(false); const lastClickWasInside = ref(false); const effectiveLoading = computed(() => props.loading); const tagPopoverVisible = ref(false); const formItemInjection = inject(formItemInjectKey, null); const foldTrigger = typeof props.showFoldTags === "string" ? props.showFoldTags : "hover"; const color = computed(() => { var _a; if (formItemInjection == null ? void 0 : formItemInjection.fieldResult.value) { return ((_a = formItemInjection == null ? void 0 : formItemInjection.fieldResult.value) == null ? void 0 : _a.type) || "normal"; } return props.color; }); const optionLabels = ref({}); const valueList = ref([]); const finalValueList = ref([]); const filterValue = ref(); const pathMap = ref({}); const parseMultipleModelValue = (v) => { const leaves = []; const paths = {}; if (!isArray(v)) { return { leaves, paths }; } v.forEach((item) => { if (props.emitPath && isArray(item)) { const path = item; const leaf = path[path.length - 1]; leaves.push(leaf); paths[leaf] = path; return; } leaves.push(item); }); return { leaves, paths }; }; const parseSingleModelValue = (v) => { const leaves = []; const paths = {}; if (props.emitPath && isArray(v) && v.length > 0) { const path = v; const leaf = path[path.length - 1]; leaves.push(leaf); paths[leaf] = path; return { leaves, paths }; } if (isArray(v)) { const arr = v; if (arr.length > 0) leaves.push(arr[arr.length - 1]); return { leaves, paths }; } if (!isUndefined(v)) { leaves.push(v); } return { leaves, paths }; }; const parseModelValue = (v) => { return props.multiple ? parseMultipleModelValue(v) : parseSingleModelValue(v); }; const { leaves: initLeaves, paths: initPaths } = parseModelValue(props.modelValue); valueList.value = initLeaves; Object.assign(pathMap.value, initPaths); finalValueList.value = [...valueList.value]; const valueListDisplay = computed(() => { if (!props.maxTagCount) { return finalValueList.value; } return finalValueList.value.slice(0, props.maxTagCount); }); const valueListFold = computed(() => { if (!props.maxTagCount) { return []; } return finalValueList.value.slice(props.maxTagCount); }); const foldLabel = computed(() => { if (props.foldLabel) { const tags = valueListFold.value.map((item) => ({ value: item, label: optionLabels.value[item] })); return props.foldLabel(tags); } return `+${valueListFold.value.length}`; }); const isClearable = computed( () => props.clearable && !props.disabled && (valueList.value.some((v) => v !== "" && !isUndefined(v)) || Boolean(filterValue.value)) ); watch( () => props.modelValue, (v) => { const { leaves, paths } = parseModelValue(v); if (props.multiple) { if (!isArrayEqual(leaves, valueList.value)) { valueList.value = leaves; } } else { valueList.value = leaves; } Object.assign(pathMap.value, paths); finalValueList.value = [...valueList.value]; } ); const getEmitValue = (value) => { if (props.emitPath) { if (props.multiple) { return value.map((v) => pathMap.value[v] ?? [v]); } else { const leaf = value[0]; return leaf !== void 0 ? pathMap.value[leaf] ?? [leaf] : void 0; } } else { if (props.multiple) { return [...value]; } else { return value[0]; } } }; const emitChange = (value) => { var _a, _b; emits("change", getEmitValue(value)); (_b = formItemInjection == null ? void 0 : (_a = formItemInjection.fieldHandlers).onChange) == null ? void 0 : _b.call(_a); }; const emitUpdateValue = (value) => { emits("update:modelValue", getEmitValue(value)); }; const clearClick = (e) => { e.stopPropagation(); valueList.value = []; finalValueList.value = []; pathMap.value = {}; filterValue.value = ""; emits("clear", e); emitChange(valueList.value); emitUpdateValue(valueList.value); }; const resolveSelectValue = async (value) => { if (!isFunction(props.beforeSelect)) return value; const rlt = await props.beforeSelect(value, props.multiple ? valueList.value : valueList.value[0]); if (rlt === false) return null; return typeof rlt === "boolean" ? value : rlt; }; const applySingleSelect = (toValue) => { if (valueList.value[0] === toValue) return; valueList.value[0] = toValue; emitUpdateValue(valueList.value); emitChange(valueList.value); }; const applyMultipleSelect = (toValue) => { const idx = valueList.value.indexOf(toValue); if (idx > -1) { valueList.value.splice(idx, 1); } else { valueList.value.push(toValue); } emitUpdateValue(valueList.value); emitChange(valueList.value); if (props.filterable) { filterValue.value = ""; } }; const handleInput = (e) => { const input = e.target; filterValue.value = input.value; }; provide(cascaderV2InjectKey, { multiple: props.multiple, allowSelectAnyNode: props.allowSelectAnyNode, selectValue: valueList, filterValue, isSelecting, loading: computed(() => props.loading), doSelectBatch(toAdd, toRemove) { toAdd.forEach((item) => { if (!valueList.value.includes(item.value)) { valueList.value.push(item.value); optionLabels.value[item.value] = item.label; pathMap.value[item.value] = item.path; } }); toRemove.forEach((v) => { const idx = valueList.value.indexOf(v); if (idx > -1) valueList.value.splice(idx, 1); }); emitUpdateValue(valueList.value); emitChange(valueList.value); }, doSelect: async (option, path) => { const toValue = await resolveSelectValue(option.value); if (toValue === null) return; if (path && toValue === option.value) { pathMap.value[toValue] = path; } if (props.multiple) { applyMultipleSelect(toValue); return; } applySingleSelect(toValue); }, registerOption(option) { if (optionLabels.value[option.value] !== option.label) { optionLabels.value[option.value] = option.label; } }, registerPath(value, path) { pathMap.value[value] = path; }, hidePanel() { isSelecting.value = false; }, showPanel() { isSelecting.value = true; }, setRootLoading(v) { lazyRootLoading.value = v; }, onLazyloadError(node) { emits("lazyload-error", node); } }); const onOptionVisibleChange = (visible) => { emits("options-visible-change", visible); }; const onRemoveTag = (value, e) => { if (props.disabled) { return; } e.stopPropagation(); const idx = valueList.value.indexOf(value); if (idx > -1) { valueList.value.splice(idx, 1); emitChange(valueList.value); emitUpdateValue(valueList.value); } }; const onFoldTagClick = (e) => { if (foldTrigger === "click") { e.stopPropagation(); } }; const beforeTagPopoverShow = () => { if (props.disabled) { return false; } return true; }; const handleClickEvent = (e) => { if (props.disabled) { e.stopPropagation(); e.preventDefault(); return false; } lastClickWasInside.value = true; if (props.filterable && inputRef.value && e.target !== inputRef.value) { inputRef.value.focus(); } }; const handleMouseLeave = () => { lastClickWasInside.value = false; }; const beforeOptionsHide = () => { if (props.filterable && lastClickWasInside.value) { return false; } if (isFunction(props.beforeOptionsHide)) { return props.beforeOptionsHide(); } return true; }; watch(filterValue, async () => { await nextTick(); if (props.filterable && valueListDisplay.value.length > 0 && inputMirrorRef.value) { inputWidth.value = Math.max(12, inputMirrorRef.value.offsetWidth + 2); } else { inputWidth.value = 12; } }); watch( () => isSelecting.value, (newVal) => { if (newVal) { tagPopoverVisible.value = false; if (props.filterable) { nextTick(() => { if (inputRef.value) { inputRef.value.focus(); } }); } } else { filterValue.value = ""; } } ); return (_ctx, _cache) => { return openBlock(), createBlock(unref(_sfc_main$1), mergeProps({ ref_key: "cascaderV2Ref", ref: cascaderV2Ref }, { size: props.size, variant: props.variant, color: color.value, disabled: props.disabled, round: props.round, focused: isSelecting.value }, { class: ["o-cascader-v2", [ `o-cascader-v2-${props.size}`, { "is-selecting": isSelecting.value, "is-multiple": props.multiple && valueList.value.length > 0, "o-cascader-v2-clearable": isClearable.value, "o-cascader-v2-is-loading": effectiveLoading.value } ]], onClick: handleClickEvent, onMouseleave: handleMouseLeave }), { default: withCtx(() => [ createVNode(unref(OScroller), { class: "o-cascader-v2-tags-scroller", "wrap-class": "o-cascader-v2-value-list", "show-type": "hover", size: "small", "disabled-y": props.disabled, "disabled-x": "" }, { default: withCtx(() => [ !props.multiple || props.multiple && valueList.value.length === 0 ? (openBlock(), createElementBlock("input", { key: 0, ref_key: "inputRef", ref: inputRef, disabled: props.disabled, value: filterValue.value || optionLabels.value[valueList.value[0]], placeholder: props.placeholder, readonly: !props.filterable, type: "text", class: "o-cascader-v2-input", onInput: handleInput }, null, 40, _hoisted_1)) : (openBlock(), createElementBlock("div", _hoisted_2, [ (openBlock(true), createElementBlock( Fragment, null, renderList(valueListDisplay.value, (item) => { return openBlock(), createElementBlock("div", { key: item, class: "o-cascader-v2-tag" }, [ createElementVNode( "span", _hoisted_3, toDisplayString(optionLabels.value[item]), 1 /* TEXT */ ), createElementVNode("div", { class: normalizeClass(["o-cascader-v2-tag-remove", { "o-cascader-v2-tag-remove-disabled": props.disabled }]), onClick: (e) => onRemoveTag(item, e) }, [ createVNode(unref(IconClose)) ], 10, _hoisted_4) ]); }), 128 /* KEYED_FRAGMENT */ )), _ctx.showFoldTags && valueListFold.value.length > 0 ? (openBlock(), createBlock(unref(OPopover), { key: 0, visible: tagPopoverVisible.value, "onUpdate:visible": _cache[0] || (_cache[0] = ($event) => tagPopoverVisible.value = $event), trigger: unref(foldTrigger), "before-show": beforeTagPopoverShow, disabled: props.disabled, "wrap-class": "o-cascader-v2-tag-popover", position: "top" }, { target: withCtx(() => [ createElementVNode("div", { class: "o-cascader-v2-tag", onClick: onFoldTagClick }, [ renderSlot(_ctx.$slots, "tag-fold", {}, () => [ createTextVNode( toDisplayString(foldLabel.value), 1 /* TEXT */ ) ]) ]) ]), default: withCtx(() => [ createElementVNode("div", _hoisted_5, [ (openBlock(true), createElementBlock( Fragment, null, renderList(valueListFold.value, (item) => { return openBlock(), createElementBlock("div", { key: item, class: "o-cascader-v2-tag" }, [ createElementVNode( "span", _hoisted_6, toDisplayString(optionLabels.value[item]), 1 /* TEXT */ ), createElementVNode("div", { class: normalizeClass(["o-cascader-v2-tag-remove", { "o-cascader-v2-tag-remove-disabled": props.disabled }]), onClick: (e) => onRemoveTag(item, e) }, [ createVNode(unref(IconClose)) ], 10, _hoisted_7) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]), _: 3 /* FORWARDED */ }, 8, ["visible", "trigger", "disabled"])) : createCommentVNode("v-if", true), createCommentVNode(" 镜像元素,可搜索模式下用于动态测量输入框宽度 "), props.filterable && valueListDisplay.value.length > 0 ? (openBlock(), createElementBlock( "span", { key: 1, ref_key: "inputMirrorRef", ref: inputMirrorRef, class: "o-cascader-v2-input-mirror", "aria-hidden": "true" }, toDisplayString(filterValue.value || ""), 513 /* TEXT, NEED_PATCH */ )) : createCommentVNode("v-if", true), createCommentVNode(" 多选搜索框 "), props.filterable ? (openBlock(), createElementBlock("input", { key: 2, ref_key: "inputRef", ref: inputRef, value: filterValue.value, readonly: !props.filterable, disabled: props.disabled, type: "text", class: "o-cascader-v2-input", style: normalizeStyle(props.filterable && valueListDisplay.value.length > 0 ? { width: `${inputWidth.value}px` } : { width: "100%" }), onInput: handleInput }, null, 44, _hoisted_8)) : createCommentVNode("v-if", true) ])), createElementVNode("div", _hoisted_9, [ createElementVNode("div", _hoisted_10, [ effectiveLoading.value ? (openBlock(), createElementBlock("div", _hoisted_11, [ createVNode(unref(IconLoading), { class: "o-rotating" }) ])) : isClearable.value ? (openBlock(), createElementBlock("div", { key: 1, class: "o-cascader-v2-clear", onClick: clearClick }, [ createVNode(unref(IconClose), { class: "o-cascader-v2-clear-icon" }) ])) : createCommentVNode("v-if", true), createElementVNode( "div", { class: normalizeClass(["o-cascader-v2-arrow", { active: isSelecting.value }]) }, [ renderSlot(_ctx.$slots, "arrow", { active: isSelecting.value }, () => [ createVNode(unref(IconChevronDown)) ]) ], 2 /* CLASS */ ) ]), renderSlot(_ctx.$slots, "suffix", { active: isSelecting.value }) ]) ]), _: 3 /* FORWARDED */ }, 8, ["disabled-y"]), createVNode(unref(ClientOnly), null, { default: withCtx(() => [ (openBlock(), createBlock(Teleport, { to: cascaderv2Panel.value, disabled: !cascaderv2Panel.value }, [ withDirectives(createElementVNode( "div", null, [ renderSlot(_ctx.$slots, "default", {}, () => [ createVNode(_sfc_main$2, { options: props.options, "model-value": props.modelValue, "path-mode": props.pathMode, "expand-trigger": props.expandTrigger, size: props.size, "show-all-levels": props.showAllLevels, filterable: props.filterable, lazy: props.lazy, lazyload: props.lazyload }, null, 8, ["options", "model-value", "path-mode", "expand-trigger", "size", "show-all-levels", "filterable", "lazy", "lazyload"]) ]) ], 512 /* NEED_PATCH */ ), [ [vShow, cascaderv2Panel.value] ]) ], 8, ["to", "disabled"])), !props.disabled ? (openBlock(), createBlock(unref(OPopup), { key: 0, visible: isSelecting.value, "onUpdate:visible": _cache[1] || (_cache[1] = ($event) => isSelecting.value = $event), transition: props.transition, "unmount-on-hide": props.unmountOnHide, position: props.optionPosition, wrapper: props.optionsWrapper, target: cascaderV2El.value, trigger: props.trigger, "adjust-min-width": props.optionWidthMode === "min-width", "adjust-width": props.optionWidthMode === "width", "before-show": props.beforeOptionsShow, "before-hide": beforeOptionsHide, offset: 4, "wrap-class": "o-cascader-v2-panel-popup", onChange: onOptionVisibleChange }, { default: withCtx(() => [ createElementVNode( "div", { ref_key: "cascaderv2Panel", ref: cascaderv2Panel }, null, 512 /* NEED_PATCH */ ) ]), _: 1 /* STABLE */ }, 8, ["visible", "transition", "unmount-on-hide", "position", "wrapper", "target", "trigger", "adjust-min-width", "adjust-width", "before-show"])) : createCommentVNode("v-if", true), createCommentVNode(" TODO 移动端 ") ]), _: 3 /* FORWARDED */ }) ]), _: 3 /* FORWARDED */ }, 16, ["class"]); }; } }); export { _sfc_main as default };