UNPKG

@opensig/opendesign

Version:

607 lines (606 loc) 23.3 kB
"use strict"; const vue = require("vue"); const icons = require("../_utils/icons.js"); const index$2 = require("../popup/index.js"); const index$1 = require("../popover/index.js"); const index = require("../scrollbar/index.js"); const clientOnly = require("../_components/client-only.js"); const InBox_vue_vue_type_script_setup_true_lang = require("../_components/in-box/InBox.vue.js"); const OCascaderV2Panel_vue_vue_type_script_setup_true_lang = require("./OCascaderV2Panel.vue.js"); const is = require("../_utils/is.js"); const provide = require("../form/provide.js"); const provide$1 = require("./provide.js"); const types = require("./types.js"); 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__ */ vue.defineComponent({ __name: "OCascaderV2", props: types.cascaderV2Props, emits: ["update:modelValue", "change", "options-visible-change", "clear", "lazyload-error"], setup(__props, { emit: __emit }) { const props = __props; const emits = __emit; const cascaderV2Ref = vue.ref(); const cascaderV2El = vue.computed(() => { var _a; return (_a = cascaderV2Ref.value) == null ? void 0 : _a.$el; }); const cascaderv2Panel = vue.ref(); const inputRef = vue.ref(); const inputMirrorRef = vue.ref(); const inputWidth = vue.ref(12); const isSelecting = vue.ref(false); const lazyRootLoading = vue.ref(false); const lastClickWasInside = vue.ref(false); const effectiveLoading = vue.computed(() => props.loading); const tagPopoverVisible = vue.ref(false); const formItemInjection = vue.inject(provide.formItemInjectKey, null); const foldTrigger = typeof props.showFoldTags === "string" ? props.showFoldTags : "hover"; const color = vue.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 = vue.ref({}); const valueList = vue.ref([]); const finalValueList = vue.ref([]); const filterValue = vue.ref(); const pathMap = vue.ref({}); const parseMultipleModelValue = (v) => { const leaves = []; const paths = {}; if (!is.isArray(v)) { return { leaves, paths }; } v.forEach((item) => { if (props.emitPath && is.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 && is.isArray(v) && v.length > 0) { const path = v; const leaf = path[path.length - 1]; leaves.push(leaf); paths[leaf] = path; return { leaves, paths }; } if (is.isArray(v)) { const arr = v; if (arr.length > 0) leaves.push(arr[arr.length - 1]); return { leaves, paths }; } if (!is.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 = vue.computed(() => { if (!props.maxTagCount) { return finalValueList.value; } return finalValueList.value.slice(0, props.maxTagCount); }); const valueListFold = vue.computed(() => { if (!props.maxTagCount) { return []; } return finalValueList.value.slice(props.maxTagCount); }); const foldLabel = vue.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 = vue.computed( () => props.clearable && !props.disabled && (valueList.value.some((v) => v !== "" && !is.isUndefined(v)) || Boolean(filterValue.value)) ); vue.watch( () => props.modelValue, (v) => { const { leaves, paths } = parseModelValue(v); if (props.multiple) { if (!is.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 (!is.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; }; vue.provide(provide$1.cascaderV2InjectKey, { multiple: props.multiple, allowSelectAnyNode: props.allowSelectAnyNode, selectValue: valueList, filterValue, isSelecting, loading: vue.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 (is.isFunction(props.beforeOptionsHide)) { return props.beforeOptionsHide(); } return true; }; vue.watch(filterValue, async () => { await vue.nextTick(); if (props.filterable && valueListDisplay.value.length > 0 && inputMirrorRef.value) { inputWidth.value = Math.max(12, inputMirrorRef.value.offsetWidth + 2); } else { inputWidth.value = 12; } }); vue.watch( () => isSelecting.value, (newVal) => { if (newVal) { tagPopoverVisible.value = false; if (props.filterable) { vue.nextTick(() => { if (inputRef.value) { inputRef.value.focus(); } }); } } else { filterValue.value = ""; } } ); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.unref(InBox_vue_vue_type_script_setup_true_lang), vue.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: vue.withCtx(() => [ vue.createVNode(vue.unref(index.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: vue.withCtx(() => [ !props.multiple || props.multiple && valueList.value.length === 0 ? (vue.openBlock(), vue.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)) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_2, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList(valueListDisplay.value, (item) => { return vue.openBlock(), vue.createElementBlock("div", { key: item, class: "o-cascader-v2-tag" }, [ vue.createElementVNode( "span", _hoisted_3, vue.toDisplayString(optionLabels.value[item]), 1 /* TEXT */ ), vue.createElementVNode("div", { class: vue.normalizeClass(["o-cascader-v2-tag-remove", { "o-cascader-v2-tag-remove-disabled": props.disabled }]), onClick: (e) => onRemoveTag(item, e) }, [ vue.createVNode(vue.unref(icons.IconClose)) ], 10, _hoisted_4) ]); }), 128 /* KEYED_FRAGMENT */ )), _ctx.showFoldTags && valueListFold.value.length > 0 ? (vue.openBlock(), vue.createBlock(vue.unref(index$1.OPopover), { key: 0, visible: tagPopoverVisible.value, "onUpdate:visible": _cache[0] || (_cache[0] = ($event) => tagPopoverVisible.value = $event), trigger: vue.unref(foldTrigger), "before-show": beforeTagPopoverShow, disabled: props.disabled, "wrap-class": "o-cascader-v2-tag-popover", position: "top" }, { target: vue.withCtx(() => [ vue.createElementVNode("div", { class: "o-cascader-v2-tag", onClick: onFoldTagClick }, [ vue.renderSlot(_ctx.$slots, "tag-fold", {}, () => [ vue.createTextVNode( vue.toDisplayString(foldLabel.value), 1 /* TEXT */ ) ]) ]) ]), default: vue.withCtx(() => [ vue.createElementVNode("div", _hoisted_5, [ (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList(valueListFold.value, (item) => { return vue.openBlock(), vue.createElementBlock("div", { key: item, class: "o-cascader-v2-tag" }, [ vue.createElementVNode( "span", _hoisted_6, vue.toDisplayString(optionLabels.value[item]), 1 /* TEXT */ ), vue.createElementVNode("div", { class: vue.normalizeClass(["o-cascader-v2-tag-remove", { "o-cascader-v2-tag-remove-disabled": props.disabled }]), onClick: (e) => onRemoveTag(item, e) }, [ vue.createVNode(vue.unref(icons.IconClose)) ], 10, _hoisted_7) ]); }), 128 /* KEYED_FRAGMENT */ )) ]) ]), _: 3 /* FORWARDED */ }, 8, ["visible", "trigger", "disabled"])) : vue.createCommentVNode("v-if", true), vue.createCommentVNode(" 镜像元素,可搜索模式下用于动态测量输入框宽度 "), props.filterable && valueListDisplay.value.length > 0 ? (vue.openBlock(), vue.createElementBlock( "span", { key: 1, ref_key: "inputMirrorRef", ref: inputMirrorRef, class: "o-cascader-v2-input-mirror", "aria-hidden": "true" }, vue.toDisplayString(filterValue.value || ""), 513 /* TEXT, NEED_PATCH */ )) : vue.createCommentVNode("v-if", true), vue.createCommentVNode(" 多选搜索框 "), props.filterable ? (vue.openBlock(), vue.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: vue.normalizeStyle(props.filterable && valueListDisplay.value.length > 0 ? { width: `${inputWidth.value}px` } : { width: "100%" }), onInput: handleInput }, null, 44, _hoisted_8)) : vue.createCommentVNode("v-if", true) ])), vue.createElementVNode("div", _hoisted_9, [ vue.createElementVNode("div", _hoisted_10, [ effectiveLoading.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11, [ vue.createVNode(vue.unref(icons.IconLoading), { class: "o-rotating" }) ])) : isClearable.value ? (vue.openBlock(), vue.createElementBlock("div", { key: 1, class: "o-cascader-v2-clear", onClick: clearClick }, [ vue.createVNode(vue.unref(icons.IconClose), { class: "o-cascader-v2-clear-icon" }) ])) : vue.createCommentVNode("v-if", true), vue.createElementVNode( "div", { class: vue.normalizeClass(["o-cascader-v2-arrow", { active: isSelecting.value }]) }, [ vue.renderSlot(_ctx.$slots, "arrow", { active: isSelecting.value }, () => [ vue.createVNode(vue.unref(icons.IconChevronDown)) ]) ], 2 /* CLASS */ ) ]), vue.renderSlot(_ctx.$slots, "suffix", { active: isSelecting.value }) ]) ]), _: 3 /* FORWARDED */ }, 8, ["disabled-y"]), vue.createVNode(vue.unref(clientOnly), null, { default: vue.withCtx(() => [ (vue.openBlock(), vue.createBlock(vue.Teleport, { to: cascaderv2Panel.value, disabled: !cascaderv2Panel.value }, [ vue.withDirectives(vue.createElementVNode( "div", null, [ vue.renderSlot(_ctx.$slots, "default", {}, () => [ vue.createVNode(OCascaderV2Panel_vue_vue_type_script_setup_true_lang, { 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 */ ), [ [vue.vShow, cascaderv2Panel.value] ]) ], 8, ["to", "disabled"])), !props.disabled ? (vue.openBlock(), vue.createBlock(vue.unref(index$2.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: vue.withCtx(() => [ vue.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"])) : vue.createCommentVNode("v-if", true), vue.createCommentVNode(" TODO 移动端 ") ]), _: 3 /* FORWARDED */ }) ]), _: 3 /* FORWARDED */ }, 16, ["class"]); }; } }); module.exports = _sfc_main;