@opensig/opendesign
Version:
675 lines (674 loc) • 26.8 kB
JavaScript
;
const vue = require("vue");
const index$1 = require("../scrollbar/index.js");
const index$2 = require("../divider/index.js");
const icons = require("../_utils/icons.js");
const is = require("../_utils/is.js");
const index = require("../locale/index.js");
const cascader = require("../cascader/cascader.js");
const types = require("./types.js");
const provide = require("./provide.js");
const OCascaderV2Label_vue_vue_type_script_setup_true_lang = require("./OCascaderV2Label.vue.js");
const _hoisted_1 = { class: "o-cascader-v2-panel-loading" };
const _hoisted_2 = ["onClick"];
const _hoisted_3 = {
key: 1,
class: "o-cascader-v2-panel-empty"
};
const _hoisted_4 = { class: "o-cascader-v2-options" };
const _hoisted_5 = ["onClick", "onMouseenter"];
const ROOT_KEY = "__root__";
const _sfc_main = /* @__PURE__ */ vue.defineComponent({
__name: "OCascaderV2Panel",
props: types.cascaderV2PanelProps,
emits: ["change", "update:modelValue"],
setup(__props, { emit: __emit }) {
const cascaderV2Inject = vue.inject(provide.cascaderV2InjectKey, null);
const props = __props;
const emits = __emit;
const { t } = index.useI18n();
const isMultiple = cascaderV2Inject == null ? void 0 : cascaderV2Inject.multiple;
const allowSelectAnyNode = (cascaderV2Inject == null ? void 0 : cascaderV2Inject.allowSelectAnyNode) ?? false;
const filterValue = cascaderV2Inject == null ? void 0 : cascaderV2Inject.filterValue;
const isSelecting = cascaderV2Inject == null ? void 0 : cascaderV2Inject.isSelecting;
const isLoading = cascaderV2Inject == null ? void 0 : cascaderV2Inject.loading;
const cascaderTree = new cascader();
const lazyLoadState = vue.ref({});
const panelInfo = vue.ref();
const selectedVal = vue.computed(() => {
return (cascaderV2Inject == null ? void 0 : cascaderV2Inject.selectValue.value) ?? [];
});
const selectedLeafNode = vue.computed(() => {
return selectedVal.value.map((val) => {
const node = cascaderTree.getNode(val);
if (!node || !node.isLeaf) {
return;
}
return node;
}).filter(Boolean);
});
const selectedLeafPath = vue.computed(() => {
return selectedLeafNode.value.map((val) => {
return val == null ? void 0 : val.fullPath;
}).filter((item) => item == null ? void 0 : item.length);
});
const isNodeFullySelected = (val) => {
const node = cascaderTree.getNode(val);
if (!node) return false;
if (node.isLeaf) return selectedVal.value.includes(val);
return node.children.length > 0 && node.children.every((child) => isNodeFullySelected(child.value));
};
const innerExpandTrigger = vue.computed(() => {
if (is.isTouchDevice) {
return "click";
}
if (props.expandTrigger === "hover" || props.expandTrigger === "click") {
return props.expandTrigger;
}
return "click";
});
const leafNodes = vue.ref([]);
const collectAllDescendants = (root) => {
const result = [];
const dfs = (node) => {
for (const child of node.children) {
result.push(child);
dfs(child);
}
};
dfs(root);
return result;
};
const splitLabelByKeyword = (label, keyword) => {
const parts = [];
let lastIndex = 0;
while (true) {
const index2 = label.indexOf(keyword, lastIndex);
if (index2 === -1) break;
if (index2 > lastIndex) {
parts.push({ text: label.substring(lastIndex, index2), isHighlighted: false });
}
parts.push({ text: label.substring(index2, index2 + keyword.length), isHighlighted: true });
lastIndex = index2 + keyword.length;
}
if (lastIndex < label.length) {
parts.push({ text: label.substring(lastIndex), isHighlighted: false });
}
return parts;
};
const filteredOptions = vue.computed(() => {
if (!props.filterable || !(cascaderV2Inject == null ? void 0 : cascaderV2Inject.filterValue.value)) {
return [];
}
const searchValue = cascaderV2Inject.filterValue.value;
const sourceNodes = allowSelectAnyNode ? (void leafNodes.value, collectAllDescendants(cascaderTree.root)) : leafNodes.value;
return sourceNodes.filter((item) => item.fullLabel.includes(searchValue)).map((node) => ({
label: node.fullLabel,
labelParts: splitLabelByKeyword(node.fullLabel, searchValue),
value: node.value,
disabled: node.disabled,
isActive: selectedVal.value.includes(node.value),
isLeaf: node.isLeaf
}));
});
const updateSelectedValue = (option, doSelect = true, path) => {
cascaderV2Inject == null ? void 0 : cascaderV2Inject.registerOption(option);
if (path) {
cascaderV2Inject == null ? void 0 : cascaderV2Inject.registerPath(option.value, path);
}
if (doSelect) {
cascaderV2Inject == null ? void 0 : cascaderV2Inject.doSelect(option, path);
}
};
const hidePanel = (shouldHide) => {
if (!shouldHide) {
return;
}
cascaderV2Inject == null ? void 0 : cascaderV2Inject.hidePanel();
};
const isNonLeafPathCovered = (currPath) => {
const currLen = currPath.length;
return selectedLeafPath.value.some((path) => {
if (path) {
const pathLen = path.length;
return is.isArrayEqual(currPath, path.slice(0, currLen - pathLen));
}
});
};
const deactivateAllNonLeafNodesInColumn = (columnInfo) => {
columnInfo.forEach((item) => {
item.isActive = !item.isLeaf ? false : item.isActive;
});
};
const initColumnInfo = (columnInfo) => {
columnInfo.forEach((item) => {
if (!item.isLeaf) {
item.hasActiveChild = allowSelectAnyNode ? false : isNonLeafPathCovered(item.fullPath);
return;
}
if (selectedVal.value.includes(item.value)) {
item.isActive = true;
}
});
};
const refrashCheckStateByBubble = (option, columnInfo) => {
if (allowSelectAnyNode) {
return;
}
const depth = option.depth;
if (depth < 2) {
return;
}
const hasActiveChild = columnInfo.some((item) => item.isLeaf && item.isActive || item.hasActiveChild);
const prevColumnInfo = panelInfo.value[depth - 2];
const parentOption = prevColumnInfo.find((item) => {
var _a;
return item.value === ((_a = option.parent) == null ? void 0 : _a.value);
});
if (!parentOption) {
return;
}
parentOption.hasActiveChild = hasActiveChild;
refrashCheckStateByBubble(parentOption, prevColumnInfo);
};
const getOptionList = () => {
var _a;
const panelInfoLen = ((_a = panelInfo.value) == null ? void 0 : _a.length) || 0;
const nonLeafOptionList = [];
for (let i = 0; i < panelInfoLen; i++) {
const columnInfo = panelInfo.value[i];
const columnInfoLen = columnInfo.length;
for (let j = 0; j < columnInfoLen; j++) {
const currOption = columnInfo[j];
if (!currOption.isLeaf) {
nonLeafOptionList.push(currOption);
continue;
}
if (selectedVal.value.includes(currOption.value)) {
currOption.isActive = true;
} else {
currOption.isActive = false;
}
}
}
return nonLeafOptionList;
};
const refrashCheckStateByCapture = () => {
const nonLeafOptionList = getOptionList();
nonLeafOptionList.forEach((option) => {
option.hasActiveChild = allowSelectAnyNode ? false : isNonLeafPathCovered(option.fullPath);
});
};
const selectOption = (option, columnInfo) => {
var _a;
while (option.depth < panelInfo.value.length) {
(_a = panelInfo.value) == null ? void 0 : _a.pop();
}
if (isMultiple) {
option.isActive = !option.isActive;
deactivateAllNonLeafNodesInColumn(columnInfo);
if (!allowSelectAnyNode) {
refrashCheckStateByBubble(option, columnInfo);
}
} else {
columnInfo.forEach((item) => {
item.isActive = item.value === option.value;
});
}
const { label, fullLabel, value, fullPath } = option;
const simpleVal = value;
if (props.pathMode) {
emits("change", fullPath);
emits("update:modelValue", fullPath);
} else {
emits("change", simpleVal);
emits("update:modelValue", simpleVal);
}
updateSelectedValue({ label: props.showAllLevels ? fullLabel : label ?? "", value }, true, fullPath);
};
const selectNonLeafStrict = (option) => {
updateSelectedValue({ label: props.showAllLevels ? option.fullLabel : option.label ?? "", value: option.value }, true, option.fullPath);
};
const getLeafDescendants = (nodeValue) => {
const node = cascaderTree.getNode(nodeValue);
if (!node) return [];
const leaves = [];
const traverse = (n) => {
if (n.isLeaf) {
leaves.push(n);
} else {
n.children.forEach(traverse);
}
};
node.children.forEach(traverse);
return leaves;
};
const toggleNonLeafDescendants = (option) => {
const leaves = getLeafDescendants(option.value);
if (!leaves.length) return;
if (isNodeFullySelected(option.value)) {
cascaderV2Inject == null ? void 0 : cascaderV2Inject.doSelectBatch(
[],
leaves.map((l) => l.value)
);
} else {
const toAdd = leaves.filter((l) => !l.disabled).map((l) => ({
value: l.value,
label: props.showAllLevels ? l.fullLabel : l.label ?? "",
path: l.fullPath
}));
cascaderV2Inject == null ? void 0 : cascaderV2Inject.doSelectBatch(toAdd, []);
}
refrashCheckStateByCapture();
};
const syncColumnActiveState = (option, columnInfo) => {
if (isMultiple) {
deactivateAllNonLeafNodesInColumn(columnInfo);
option.isActive = !option.isActive;
return;
}
columnInfo.forEach((item) => {
item.isActive = item.value === option.value;
});
};
const pushChildrenColumn = (node) => {
const nextColumnInfo = cascaderTree.getColumnInfo(node, selectedVal.value);
initColumnInfo(nextColumnInfo);
panelInfo.value.push(nextColumnInfo);
};
const triggerLazyLoad = (option, node) => {
var _a;
lazyLoadState.value[String(option.value)] = "loading";
const lazyNode = {
value: node.value,
level: node.depth,
isLeaf: node.isLeaf,
data: { value: node.value, label: node.label },
path: node.fullPath,
label: node.fullLabel
};
const nodeResolve = (children) => {
cascaderTree.addChildren(node.value, children, true);
leafNodes.value = cascaderTree.getLeafNodes();
lazyLoadState.value[String(option.value)] = "loaded";
const updatedNode = cascaderTree.getNode(option.value);
if (updatedNode) {
option.isLeaf = updatedNode.isLeaf;
}
if (!option.isLeaf && updatedNode) {
pushChildrenColumn(updatedNode);
}
};
const nodeReject = () => {
lazyLoadState.value[String(option.value)] = "error";
cascaderV2Inject == null ? void 0 : cascaderV2Inject.onLazyloadError(lazyNode);
};
const result = (_a = props.lazyload) == null ? void 0 : _a.call(props, lazyNode, nodeResolve, nodeReject);
if (result instanceof Promise) {
result.then(nodeResolve).catch(nodeReject);
}
};
const expandOption = (option, columnInfo) => {
var _a;
if (props.lazy && lazyLoadState.value[String(option.value)] === "loading") return;
while (option.depth < panelInfo.value.length) {
(_a = panelInfo.value) == null ? void 0 : _a.pop();
}
syncColumnActiveState(option, columnInfo);
const node = cascaderTree.getNode(option.value);
if (!node) return;
if (props.lazy && props.lazyload && lazyLoadState.value[String(option.value)] !== "loaded") {
triggerLazyLoad(option, node);
return;
}
pushChildrenColumn(node);
};
const selectNonLeafOption = (option) => {
if (isMultiple) {
if (allowSelectAnyNode) {
selectNonLeafStrict(option);
return;
}
toggleNonLeafDescendants(option);
return;
}
const { label, fullLabel, value, fullPath } = option;
updateSelectedValue({ label: props.showAllLevels ? fullLabel : label ?? "", value }, true, fullPath);
};
const onLabelSelect = (option, columnInfo) => {
if (!is.isArray(panelInfo.value) || option.disabled) {
return;
}
if (option.isLeaf) {
selectOption(option, columnInfo);
hidePanel(!isMultiple);
return;
}
selectNonLeafOption(option);
if (!option.isActive && innerExpandTrigger.value === "click") {
expandOption(option, columnInfo);
}
};
const onClick = (option, columnInfo) => {
if (!is.isArray(panelInfo.value) || option.disabled) {
return;
}
if (option.isLeaf) {
selectOption(option, columnInfo);
hidePanel(!isMultiple);
return;
}
if (innerExpandTrigger.value !== "click") return;
expandOption(option, columnInfo);
};
const onMouseenter = (option, columnInfo) => {
if (!is.isArray(panelInfo.value) || option.isLeaf || option.isActive || innerExpandTrigger.value !== "hover") {
return;
}
expandOption(option, columnInfo);
};
const getFinalPath = () => {
const numSet = /* @__PURE__ */ new Set();
selectedLeafPath.value.forEach((item) => {
numSet.add((item == null ? void 0 : item.length) ?? 0);
});
const maxPathLen = Math.max(...Array.from(numSet));
const filteredPathList = selectedLeafPath.value.filter((item) => (item == null ? void 0 : item.length) === maxPathLen);
return filteredPathList[filteredPathList.length - 1];
};
const buildSelectedOption = (node) => ({
label: props.showAllLevels ? node.fullLabel : node.label ?? "",
value: node.value
});
const syncMultipleSelection = () => {
selectedLeafNode.value.forEach((item) => {
updateSelectedValue(buildSelectedOption(item), false, item.fullPath);
});
if (!allowSelectAnyNode) return;
selectedVal.value.forEach((v) => {
const node = cascaderTree.getNode(v);
if (node && !node.isLeaf) {
updateSelectedValue(buildSelectedOption(node), false, node.fullPath);
}
});
};
const refreshSingleSelection = (modelValue) => {
if (!modelValue && modelValue !== 0) {
panelInfo.value = cascaderTree.root.children.length ? [cascaderTree.getColumnInfo(cascaderTree.root)] : void 0;
return;
}
panelInfo.value = cascaderTree.getPanelInfo(modelValue, props.lazy);
if (is.isArray(modelValue)) return;
const node = cascaderTree.getNode(modelValue);
if (!node) return;
updateSelectedValue(buildSelectedOption(node), true, node.fullPath);
};
const refreshCascaderV2Data = (modelValue) => {
if (is.isArray(modelValue) && modelValue.length) {
const finalPath = getFinalPath();
panelInfo.value = finalPath ? cascaderTree.getPanelInfo(finalPath, props.lazy) : [cascaderTree.getColumnInfo(cascaderTree.root)];
syncMultipleSelection();
refrashCheckStateByCapture();
return;
}
refreshSingleSelection(modelValue);
};
const loadRoot = () => {
if (!props.lazy || !props.lazyload) return;
if (lazyLoadState.value[ROOT_KEY] === "loading" || lazyLoadState.value[ROOT_KEY] === "loaded") return;
lazyLoadState.value[ROOT_KEY] = "loading";
cascaderV2Inject == null ? void 0 : cascaderV2Inject.setRootLoading(true);
const rootNode = {
value: null,
level: 0,
isLeaf: false,
data: null,
path: [],
label: ""
};
const rootResolve = (children) => {
cascaderTree.addChildren(null, children, true);
leafNodes.value = cascaderTree.getLeafNodes();
lazyLoadState.value[ROOT_KEY] = "loaded";
cascaderV2Inject == null ? void 0 : cascaderV2Inject.setRootLoading(false);
refreshCascaderV2Data(props.modelValue);
};
const rootReject = () => {
lazyLoadState.value[ROOT_KEY] = "error";
cascaderV2Inject == null ? void 0 : cascaderV2Inject.setRootLoading(false);
cascaderV2Inject == null ? void 0 : cascaderV2Inject.onLazyloadError(rootNode);
};
const result = props.lazyload(rootNode, rootResolve, rootReject);
if (result instanceof Promise) {
result.then(rootResolve).catch(rootReject);
}
};
vue.watch(
() => props.options,
(val) => {
if (!is.isUndefined(val)) {
cascaderTree.updateTree(val, props.lazy);
leafNodes.value = cascaderTree.getLeafNodes();
refreshCascaderV2Data(props.modelValue);
} else {
cascaderTree.updateTree([], props.lazy);
leafNodes.value = [];
panelInfo.value = void 0;
lazyLoadState.value = {};
}
},
{
immediate: true,
deep: true
}
);
vue.watch(
() => props.modelValue,
(newValue) => {
if (!newValue) return;
if (is.isArray(newValue)) {
syncMultipleSelection();
refrashCheckStateByCapture();
return;
}
const node = cascaderTree.getNode(newValue);
if (!node) return;
updateSelectedValue(buildSelectedOption(node), true, node.fullPath);
refrashCheckStateByCapture();
}
);
vue.watch(
() => cascaderV2Inject == null ? void 0 : cascaderV2Inject.isSelecting.value,
(val) => {
if (val) {
if (props.lazy && cascaderTree.root.children.length === 0) {
loadRoot();
} else {
refreshCascaderV2Data(props.modelValue);
}
}
}
);
vue.watch(
() => cascaderV2Inject == null ? void 0 : cascaderV2Inject.filterValue.value,
(newVal, oldVal) => {
if (oldVal && !newVal && isMultiple) {
refreshCascaderV2Data(props.modelValue);
}
}
);
const handleClick = (option) => {
if (option.disabled) {
return;
}
const node = cascaderTree.getNode(option.value);
updateSelectedValue(option, true, node == null ? void 0 : node.fullPath);
hidePanel(!isMultiple);
};
return (_ctx, _cache) => {
return vue.unref(isSelecting) ? (vue.openBlock(), vue.createElementBlock(
"div",
{
key: 0,
class: vue.normalizeClass(["o-cascader-v2-panel", [`o-cascader-v2-panel-${props.size}`]]),
onMousedown: _cache[0] || (_cache[0] = vue.withModifiers(() => {
}, ["prevent"]))
},
[
vue.unref(isLoading) ? (vue.openBlock(), vue.createBlock(vue.unref(index$1.OScroller), {
key: 0,
class: "o-cascader-v2-panel-scroller",
"wrap-class": "o-cascader-v2-panel-container",
"show-type": "hover",
size: "small",
"disabled-x": ""
}, {
default: vue.withCtx(() => [
vue.createElementVNode("div", _hoisted_1, [
vue.createVNode(vue.unref(icons.IconLoading), { class: "o-rotating" })
])
]),
_: 1
/* STABLE */
})) : props.filterable && vue.unref(filterValue) ? (vue.openBlock(), vue.createElementBlock(
vue.Fragment,
{ key: 1 },
[
filteredOptions.value.length ? (vue.openBlock(), vue.createBlock(vue.unref(index$1.OScroller), {
key: 0,
class: "o-cascader-v2-panel-scroller",
"wrap-class": "o-cascader-v2-panel-container",
"show-type": "hover",
size: "small",
"disabled-x": ""
}, {
default: vue.withCtx(() => [
vue.createElementVNode(
"ul",
{
class: vue.normalizeClass(["o-cascader-v2-options", { "o-cascader-v2-options-filterable": props.filterable }])
},
[
(vue.openBlock(true), vue.createElementBlock(
vue.Fragment,
null,
vue.renderList(filteredOptions.value, (option) => {
return vue.openBlock(), vue.createElementBlock("li", {
key: option.value,
class: vue.normalizeClass([{ "o-cascader-v2-option-selected": option.isActive, "o-cascader-v2-option-disabled": option.disabled }, "o-cascader-v2-option"]),
onClick: ($event) => handleClick(option)
}, [
vue.createVNode(OCascaderV2Label_vue_vue_type_script_setup_true_lang, {
label: option.label,
"label-parts": option.labelParts,
value: option.value,
multiple: vue.unref(isMultiple),
"allow-select-any-node": vue.unref(allowSelectAnyNode),
"is-leaf": true,
disabled: option.disabled,
"is-fully-selected": vue.unref(isMultiple) ? option.isActive : void 0,
onSelect: ($event) => handleClick({ label: option.label, value: option.value })
}, null, 8, ["label", "label-parts", "value", "multiple", "allow-select-any-node", "disabled", "is-fully-selected", "onSelect"])
], 10, _hoisted_2);
}),
128
/* KEYED_FRAGMENT */
))
],
2
/* CLASS */
)
]),
_: 1
/* STABLE */
})) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_3, [
vue.createElementVNode(
"span",
null,
vue.toDisplayString(vue.unref(t)("common.empty")),
1
/* TEXT */
)
]))
],
64
/* STABLE_FRAGMENT */
)) : (vue.openBlock(true), vue.createElementBlock(
vue.Fragment,
{ key: 2 },
vue.renderList(panelInfo.value, (columnInfo, index2) => {
return vue.openBlock(), vue.createElementBlock(
vue.Fragment,
{ key: index2 },
[
index2 > 0 ? (vue.openBlock(), vue.createBlock(vue.unref(index$2.ODivider), {
key: 0,
direction: "v",
class: "o-cascader-v2-panel-divider"
})) : vue.createCommentVNode("v-if", true),
vue.createVNode(
vue.unref(index$1.OScroller),
{
class: "o-cascader-v2-panel-scroller",
"wrap-class": "o-cascader-v2-panel-container",
"show-type": "hover",
size: "small",
"disabled-x": ""
},
{
default: vue.withCtx(() => [
vue.createElementVNode("ul", _hoisted_4, [
(vue.openBlock(true), vue.createElementBlock(
vue.Fragment,
null,
vue.renderList(columnInfo, (option) => {
return vue.openBlock(), vue.createElementBlock("li", {
key: option.value,
class: vue.normalizeClass([{
"o-cascader-v2-option-selected": option.isActive && (!option.isLeaf || !vue.unref(isMultiple)),
"o-cascader-v2-option-disabled": option.disabled
}, "o-cascader-v2-option"]),
onClick: ($event) => onClick(option, columnInfo),
onMouseenter: ($event) => onMouseenter(option, columnInfo)
}, [
vue.createVNode(OCascaderV2Label_vue_vue_type_script_setup_true_lang, {
label: option.label,
value: option.value,
multiple: vue.unref(isMultiple),
"allow-select-any-node": vue.unref(allowSelectAnyNode),
disabled: option.disabled,
"is-leaf": option.isLeaf,
indeterminate: !vue.unref(allowSelectAnyNode) && option.hasActiveChild,
"is-fully-selected": !option.isLeaf && !vue.unref(allowSelectAnyNode) && vue.unref(isMultiple) ? isNodeFullySelected(option.value) : void 0,
loading: props.lazy && lazyLoadState.value[String(option.value)] === "loading",
onSelect: ($event) => onLabelSelect(option, columnInfo)
}, null, 8, ["label", "value", "multiple", "allow-select-any-node", "disabled", "is-leaf", "indeterminate", "is-fully-selected", "loading", "onSelect"])
], 42, _hoisted_5);
}),
128
/* KEYED_FRAGMENT */
))
])
]),
_: 2
/* DYNAMIC */
},
1024
/* DYNAMIC_SLOTS */
)
],
64
/* STABLE_FRAGMENT */
);
}),
128
/* KEYED_FRAGMENT */
))
],
34
/* CLASS, NEED_HYDRATION */
)) : vue.createCommentVNode("v-if", true);
};
}
});
module.exports = _sfc_main;