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