@opensig/opendesign
Version:
608 lines (607 loc) • 23 kB
JavaScript
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
};