@wfrog/vc
Version:
vue3 组件库 vc
1,450 lines (1,436 loc) • 127 kB
JavaScript
import { defineComponent, inject, createVNode, Comment, computed, createElementBlock, openBlock, normalizeClass, unref, createCommentVNode, createBlock, withModifiers, withCtx, createElementVNode, Fragment, getCurrentInstance, ref, renderList, createTextVNode, toDisplayString, renderSlot, useSlots, provide, reactive, watch, onBeforeUpdate, onMounted, nextTick, useAttrs, withDirectives, isRef, vShow, normalizeStyle, createSlots, resolveDynamicComponent, withKeys, vModelText, Transition, mergeProps, toHandlers, onUpdated, h, resolveComponent, useTemplateRef, onBeforeUnmount } from 'vue';
import { j as isLeaf, k as focusNode, l as getSibling, e as useResizeObserver, m as useCssVar, c as useEventListener } from './CEClY-_T.mjs';
import { E as ElInput } from './D19ZZ4OA.mjs';
import { i as unique, c as castArray, u as useTooltipContentProps, E as Ee, a as ElTooltip } from './DUd8IaU9.mjs';
import { E as ElScrollbar } from './CJQcPuNK.mjs';
import { t as tagProps, E as ElTag } from './Bm4zCpG6.mjs';
import { E as ElIcon } from './m2vp1CCf.mjs';
import { Check, Loading, ArrowRight, CircleClose, ArrowDown, CaretRight } from '@element-plus/icons-vue';
import { u as useNamespace, i as isArray, a as isEmpty, j as isFunction, g as isUndefined, C as isPropAbsent, c as buildProps, N as NOOP, d as definePropType, o as isClient, x as isBoolean, e as debugWarn, w as useDebounceFn, G as isPromise, H as hasOwn, k as isNil, h as isString, s as isObject } from './E_WRn0OP.mjs';
import { u as useSizeProp, c as componentSizes } from './CS4VKsqy.mjs';
import { i as iconPropType } from '../components/icon/icon2.mjs';
import { u as useEmptyValuesProps, a as useEmptyValues } from './C5hWsUfD.mjs';
import { C as CHANGE_EVENT, U as UPDATE_MODEL_EVENT } from './Ct6q2FXg.mjs';
import { _ as _export_sfc, w as withInstall } from './D389hx_T.mjs';
import { C as ClickOutside } from './HSv8BL8o.mjs';
import { u as useLocale } from './-m34CPRn.mjs';
import { u as useFormItem, b as useFormDisabled, c as useFormSize } from './BOAz6rgm.mjs';
import { a as useComposition, u as useFocusController } from './JCIyOUEY.mjs';
import { g as getEventCode, E as EVENT_CODE } from './BJS5Pdfp.mjs';
import { c as cloneDeep } from './CyxEcbcy.mjs';
import { b as ElCheckbox, c as ElRadio } from './cUoiVgQs.mjs';
import { u as useVModel } from './eQT9aAiW.mjs';
import { r as removeClass, b as addClass } from './CD1S5tP1.mjs';
import { u as useId, f as formItemContextKey } from './8rLUmOVR.mjs';
import { i as isEqual } from './-EkpfdcW.mjs';
import { s as scrollIntoView } from './DBO1MWUI.mjs';
import { b as baseFlatten } from './C2LgraHx.mjs';
import { _ as _export_sfc$1 } from './pcqpp-6-.mjs';
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0;
/**
* Recursively flattens `array`.
*
* @static
* @memberOf _
* @since 3.0.0
* @category Array
* @param {Array} array The array to flatten.
* @returns {Array} Returns the new flattened array.
* @example
*
* _.flattenDeep([1, [2, [3, [4]], 5]]);
* // => [1, 2, 3, 4, 5]
*/
function flattenDeep(array) {
var length = array == null ? 0 : array.length;
return length ? baseFlatten(array, INFINITY) : [];
}
const CASCADER_PANEL_INJECTION_KEY = Symbol();
function isVNodeEmpty(vnodes) {
return !!(isArray(vnodes) ? vnodes.every(({
type
}) => type === Comment) : (vnodes == null ? void 0 : vnodes.type) === Comment);
}
var NodeContent$1 = defineComponent({
name: "NodeContent",
props: {
node: {
type: Object,
required: true
}
},
setup(props) {
const ns = useNamespace("cascader-node");
const {
renderLabelFn
} = inject(CASCADER_PANEL_INJECTION_KEY);
const {
node
} = props;
const {
data,
label: nodeLabel
} = node;
const label = () => {
const renderLabel = renderLabelFn == null ? void 0 : renderLabelFn({
node,
data
});
return isVNodeEmpty(renderLabel) ? nodeLabel : renderLabel != null ? renderLabel : nodeLabel;
};
return () => createVNode("span", {
"class": ns.e("label")
}, [label()]);
}
});
const __default__$5 = defineComponent({
name: "ElCascaderNode"
});
const _sfc_main$9 = /* @__PURE__ */ defineComponent({
...__default__$5,
props: {
node: {
type: Object,
required: true
},
menuId: String
},
emits: ["expand"],
setup(__props, { emit }) {
const props = __props;
const panel = inject(CASCADER_PANEL_INJECTION_KEY);
const ns = useNamespace("cascader-node");
const isHoverMenu = computed(() => panel.isHoverMenu);
const multiple = computed(() => panel.config.multiple);
const checkStrictly = computed(() => panel.config.checkStrictly);
const showPrefix = computed(() => panel.config.showPrefix);
const checkedNodeId = computed(() => {
var _a;
return (_a = panel.checkedNodes[0]) == null ? void 0 : _a.uid;
});
const isDisabled = computed(() => props.node.isDisabled);
const isLeaf = computed(() => props.node.isLeaf);
const expandable = computed(() => checkStrictly.value && !isLeaf.value || !isDisabled.value);
const inExpandingPath = computed(() => isInPath(panel.expandingNode));
const inCheckedPath = computed(() => checkStrictly.value && panel.checkedNodes.some(isInPath));
const isInPath = (node) => {
var _a;
const { level, uid } = props.node;
return ((_a = node == null ? void 0 : node.pathNodes[level - 1]) == null ? void 0 : _a.uid) === uid;
};
const doExpand = () => {
if (inExpandingPath.value)
return;
panel.expandNode(props.node);
};
const doCheck = (checked) => {
const { node } = props;
if (checked === node.checked)
return;
panel.handleCheckChange(node, checked);
};
const doLoad = () => {
panel.lazyLoad(props.node, () => {
if (!isLeaf.value)
doExpand();
});
};
const handleHoverExpand = (e) => {
if (!isHoverMenu.value)
return;
handleExpand();
!isLeaf.value && emit("expand", e);
};
const handleExpand = () => {
const { node } = props;
if (!expandable.value || node.loading)
return;
node.loaded ? doExpand() : doLoad();
};
const handleClick = () => {
if (isLeaf.value && !isDisabled.value && !checkStrictly.value && !multiple.value) {
handleCheck(true);
} else if ((panel.config.checkOnClickNode && (multiple.value || checkStrictly.value) || isLeaf.value && panel.config.checkOnClickLeaf) && !isDisabled.value) {
handleSelectCheck(!props.node.checked);
} else if (!isHoverMenu.value) {
handleExpand();
}
};
const handleSelectCheck = (checked) => {
if (checkStrictly.value) {
doCheck(checked);
if (props.node.loaded) {
doExpand();
}
} else {
handleCheck(checked);
}
};
const handleCheck = (checked) => {
if (!props.node.loaded) {
doLoad();
} else {
doCheck(checked);
!checkStrictly.value && doExpand();
}
};
return (_ctx, _cache) => {
return openBlock(), createElementBlock("li", {
id: `${__props.menuId}-${__props.node.uid}`,
role: "menuitem",
"aria-haspopup": !unref(isLeaf),
"aria-owns": unref(isLeaf) ? void 0 : __props.menuId,
"aria-expanded": unref(inExpandingPath),
tabindex: unref(expandable) ? -1 : void 0,
class: normalizeClass([
unref(ns).b(),
unref(ns).is("selectable", unref(checkStrictly)),
unref(ns).is("active", __props.node.checked),
unref(ns).is("disabled", !unref(expandable)),
unref(inExpandingPath) && "in-active-path",
unref(inCheckedPath) && "in-checked-path"
]),
onMouseenter: handleHoverExpand,
onFocus: handleHoverExpand,
onClick: handleClick
}, [
createCommentVNode(" prefix "),
unref(multiple) && unref(showPrefix) ? (openBlock(), createBlock(unref(ElCheckbox), {
key: 0,
"model-value": __props.node.checked,
indeterminate: __props.node.indeterminate,
disabled: unref(isDisabled),
onClick: withModifiers(() => {
}, ["stop"]),
"onUpdate:modelValue": handleSelectCheck
}, null, 8, ["model-value", "indeterminate", "disabled", "onClick"])) : unref(checkStrictly) && unref(showPrefix) ? (openBlock(), createBlock(unref(ElRadio), {
key: 1,
"model-value": unref(checkedNodeId),
label: __props.node.uid,
disabled: unref(isDisabled),
"onUpdate:modelValue": handleSelectCheck,
onClick: withModifiers(() => {
}, ["stop"])
}, {
default: withCtx(() => [
createCommentVNode("\n Add an empty element to avoid render label,\n do not use empty fragment here for https://github.com/vuejs/vue-next/pull/2485\n "),
createElementVNode("span")
]),
_: 1
}, 8, ["model-value", "label", "disabled", "onClick"])) : unref(isLeaf) && __props.node.checked ? (openBlock(), createBlock(unref(ElIcon), {
key: 2,
class: normalizeClass(unref(ns).e("prefix"))
}, {
default: withCtx(() => [
createVNode(unref(Check))
]),
_: 1
}, 8, ["class"])) : createCommentVNode("v-if", true),
createCommentVNode(" content "),
createVNode(unref(NodeContent$1), { node: __props.node }, null, 8, ["node"]),
createCommentVNode(" postfix "),
!unref(isLeaf) ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [
__props.node.loading ? (openBlock(), createBlock(unref(ElIcon), {
key: 0,
class: normalizeClass([unref(ns).is("loading"), unref(ns).e("postfix")])
}, {
default: withCtx(() => [
createVNode(unref(Loading))
]),
_: 1
}, 8, ["class"])) : (openBlock(), createBlock(unref(ElIcon), {
key: 1,
class: normalizeClass(["arrow-right", unref(ns).e("postfix")])
}, {
default: withCtx(() => [
createVNode(unref(ArrowRight))
]),
_: 1
}, 8, ["class"]))
], 64)) : createCommentVNode("v-if", true)
], 42, ["id", "aria-haspopup", "aria-owns", "aria-expanded", "tabindex"]);
};
}
});
var ElCascaderNode = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__file", "node.vue"]]);
const __default__$4 = defineComponent({
name: "ElCascaderMenu"
});
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
...__default__$4,
props: {
nodes: {
type: Array,
required: true
},
index: {
type: Number,
required: true
}
},
setup(__props) {
const props = __props;
const instance = getCurrentInstance();
const ns = useNamespace("cascader-menu");
const { t } = useLocale();
const id = useId();
let activeNode;
let hoverTimer;
const panel = inject(CASCADER_PANEL_INJECTION_KEY);
const hoverZone = ref();
const isEmpty = computed(() => !props.nodes.length);
const isLoading = computed(() => !panel.initialLoaded);
const menuId = computed(() => `${id.value}-${props.index}`);
const handleExpand = (e) => {
activeNode = e.target;
};
const handleMouseMove = (e) => {
if (!panel.isHoverMenu || !activeNode || !hoverZone.value)
return;
if (activeNode.contains(e.target)) {
clearHoverTimer();
const el = instance.vnode.el;
const { left } = el.getBoundingClientRect();
const { offsetWidth, offsetHeight } = el;
const startX = e.clientX - left;
const top = activeNode.offsetTop;
const bottom = top + activeNode.offsetHeight;
hoverZone.value.innerHTML = `
<path style="pointer-events: auto;" fill="transparent" d="M${startX} ${top} L${offsetWidth} 0 V${top} Z" />
<path style="pointer-events: auto;" fill="transparent" d="M${startX} ${bottom} L${offsetWidth} ${offsetHeight} V${bottom} Z" />
`;
} else if (!hoverTimer) {
hoverTimer = window.setTimeout(clearHoverZone, panel.config.hoverThreshold);
}
};
const clearHoverTimer = () => {
if (!hoverTimer)
return;
clearTimeout(hoverTimer);
hoverTimer = void 0;
};
const clearHoverZone = () => {
if (!hoverZone.value)
return;
hoverZone.value.innerHTML = "";
clearHoverTimer();
};
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(ElScrollbar), {
key: unref(menuId),
tag: "ul",
role: "menu",
class: normalizeClass(unref(ns).b()),
"wrap-class": unref(ns).e("wrap"),
"view-class": [unref(ns).e("list"), unref(ns).is("empty", unref(isEmpty))],
onMousemove: handleMouseMove,
onMouseleave: clearHoverZone
}, {
default: withCtx(() => {
var _a;
return [
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.nodes, (node) => {
return openBlock(), createBlock(ElCascaderNode, {
key: node.uid,
node,
"menu-id": unref(menuId),
onExpand: handleExpand
}, null, 8, ["node", "menu-id"]);
}), 128)),
unref(isLoading) ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(unref(ns).e("empty-text"))
}, [
createVNode(unref(ElIcon), {
size: "14",
class: normalizeClass(unref(ns).is("loading"))
}, {
default: withCtx(() => [
createVNode(unref(Loading))
]),
_: 1
}, 8, ["class"]),
createTextVNode(" " + toDisplayString(unref(t)("el.cascader.loading")), 1)
], 2)) : unref(isEmpty) ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(unref(ns).e("empty-text"))
}, [
renderSlot(_ctx.$slots, "empty", {}, () => [
createTextVNode(toDisplayString(unref(t)("el.cascader.noData")), 1)
])
], 2)) : ((_a = unref(panel)) == null ? void 0 : _a.isHoverMenu) ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
createCommentVNode(" eslint-disable-next-line vue/html-self-closing "),
(openBlock(), createElementBlock("svg", {
ref_key: "hoverZone",
ref: hoverZone,
class: normalizeClass(unref(ns).e("hover-zone"))
}, null, 2))
], 2112)) : createCommentVNode("v-if", true)
];
}),
_: 3
}, 8, ["class", "wrap-class", "view-class"]);
};
}
});
var ElCascaderMenu = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__file", "menu.vue"]]);
let uid = 0;
const calculatePathNodes = (node) => {
const nodes = [node];
let { parent } = node;
while (parent) {
nodes.unshift(parent);
parent = parent.parent;
}
return nodes;
};
let Node$1 = class Node {
constructor(data, config, parent, root = false) {
this.data = data;
this.config = config;
this.parent = parent;
this.root = root;
this.uid = uid++;
this.checked = false;
this.indeterminate = false;
this.loading = false;
const { value: valueKey, label: labelKey, children: childrenKey } = config;
const childrenData = data[childrenKey];
const pathNodes = calculatePathNodes(this);
this.level = root ? 0 : parent ? parent.level + 1 : 1;
this.value = data[valueKey];
this.label = data[labelKey];
this.pathNodes = pathNodes;
this.pathValues = pathNodes.map((node) => node.value);
this.pathLabels = pathNodes.map((node) => node.label);
this.childrenData = childrenData;
this.children = (childrenData || []).map((child) => new Node(child, config, this));
this.loaded = !config.lazy || this.isLeaf || !isEmpty(childrenData);
this.text = "";
}
get isDisabled() {
const { data, parent, config } = this;
const { disabled, checkStrictly } = config;
const isDisabled = isFunction(disabled) ? disabled(data, this) : !!data[disabled];
return isDisabled || !checkStrictly && !!(parent == null ? void 0 : parent.isDisabled);
}
get isLeaf() {
const { data, config, childrenData, loaded } = this;
const { lazy, leaf } = config;
const isLeaf = isFunction(leaf) ? leaf(data, this) : data[leaf];
return isUndefined(isLeaf) ? lazy && !loaded ? false : !(isArray(childrenData) && childrenData.length) : !!isLeaf;
}
get valueByOption() {
return this.config.emitPath ? this.pathValues : this.value;
}
appendChild(childData) {
const { childrenData, children } = this;
const node = new Node(childData, this.config, this);
if (isArray(childrenData)) {
childrenData.push(childData);
} else {
this.childrenData = [childData];
}
children.push(node);
return node;
}
calcText(allLevels, separator) {
const text = allLevels ? this.pathLabels.join(separator) : this.label;
this.text = text;
return text;
}
broadcast(checked) {
this.children.forEach((child) => {
var _a;
if (child) {
child.broadcast(checked);
(_a = child.onParentCheck) == null ? void 0 : _a.call(child, checked);
}
});
}
emit() {
var _a;
const { parent } = this;
if (parent) {
(_a = parent.onChildCheck) == null ? void 0 : _a.call(parent);
parent.emit();
}
}
onParentCheck(checked) {
if (!this.isDisabled) {
this.setCheckState(checked);
}
}
onChildCheck() {
const { children } = this;
const validChildren = children.filter((child) => !child.isDisabled);
const checked = validChildren.length ? validChildren.every((child) => child.checked) : false;
this.setCheckState(checked);
}
setCheckState(checked) {
const totalNum = this.children.length;
const checkedNum = this.children.reduce((c, p) => {
const num = p.checked ? 1 : p.indeterminate ? 0.5 : 0;
return c + num;
}, 0);
this.checked = this.loaded && this.children.filter((child) => !child.isDisabled).every((child) => child.loaded && child.checked) && checked;
this.indeterminate = this.loaded && checkedNum !== totalNum && checkedNum > 0;
}
doCheck(checked) {
if (this.checked === checked)
return;
const { checkStrictly, multiple } = this.config;
if (checkStrictly || !multiple) {
this.checked = checked;
} else {
this.broadcast(checked);
this.setCheckState(checked);
this.emit();
}
}
};
const flatNodes = (nodes, leafOnly) => {
return nodes.reduce((res, node) => {
if (node.isLeaf) {
res.push(node);
} else {
!leafOnly && res.push(node);
res = res.concat(flatNodes(node.children, leafOnly));
}
return res;
}, []);
};
class Store {
constructor(data, config) {
this.config = config;
const nodes = (data || []).map((nodeData) => new Node$1(nodeData, this.config));
this.nodes = nodes;
this.allNodes = flatNodes(nodes, false);
this.leafNodes = flatNodes(nodes, true);
}
getNodes() {
return this.nodes;
}
getFlattedNodes(leafOnly) {
return leafOnly ? this.leafNodes : this.allNodes;
}
appendNode(nodeData, parentNode) {
const node = parentNode ? parentNode.appendChild(nodeData) : new Node$1(nodeData, this.config);
if (!parentNode)
this.nodes.push(node);
this.appendAllNodesAndLeafNodes(node);
}
appendNodes(nodeDataList, parentNode) {
if (nodeDataList.length > 0) {
nodeDataList.forEach((nodeData) => this.appendNode(nodeData, parentNode));
} else {
parentNode && parentNode.isLeaf && this.leafNodes.push(parentNode);
}
}
appendAllNodesAndLeafNodes(node) {
this.allNodes.push(node);
node.isLeaf && this.leafNodes.push(node);
if (node.children) {
node.children.forEach((subNode) => {
this.appendAllNodesAndLeafNodes(subNode);
});
}
}
getNodeByValue(value, leafOnly = false) {
if (isPropAbsent(value))
return null;
const node = this.getFlattedNodes(leafOnly).find((node2) => isEqual(node2.value, value) || isEqual(node2.pathValues, value));
return node || null;
}
getSameNode(node) {
if (!node)
return null;
const node_ = this.getFlattedNodes(false).find(({ value, level }) => isEqual(node.value, value) && node.level === level);
return node_ || null;
}
}
const CommonProps = buildProps({
modelValue: {
type: definePropType([Number, String, Array, Object])
},
options: {
type: definePropType(Array),
default: () => []
},
props: {
type: definePropType(Object),
default: () => ({})
}
});
const DefaultProps = {
expandTrigger: "click",
multiple: false,
checkStrictly: false,
emitPath: true,
lazy: false,
lazyLoad: NOOP,
value: "value",
label: "label",
children: "children",
leaf: "leaf",
disabled: "disabled",
hoverThreshold: 500,
checkOnClickNode: false,
checkOnClickLeaf: true,
showPrefix: true
};
const cascaderPanelProps = buildProps({
...CommonProps,
border: {
type: Boolean,
default: true
},
renderLabel: {
type: Function
}
});
const emitChangeFn$1 = (value) => true;
const cascaderPanelEmits = {
[UPDATE_MODEL_EVENT]: emitChangeFn$1,
[CHANGE_EVENT]: emitChangeFn$1,
close: () => true,
"expand-change": (value) => value
};
const useCascaderConfig = (props) => {
return computed(() => ({
...DefaultProps,
...props.props
}));
};
const getMenuIndex = (el) => {
if (!el)
return 0;
const pieces = el.id.split("-");
return Number(pieces[pieces.length - 2]);
};
const checkNode = (el) => {
if (!el)
return;
const input = el.querySelector("input");
if (input) {
input.click();
} else if (isLeaf(el)) {
el.click();
}
};
const sortByOriginalOrder = (oldNodes, newNodes) => {
const newNodesCopy = newNodes.slice(0);
const newIds = newNodesCopy.map((node) => node.uid);
const res = oldNodes.reduce((acc, item) => {
const index = newIds.indexOf(item.uid);
if (index > -1) {
acc.push(item);
newNodesCopy.splice(index, 1);
newIds.splice(index, 1);
}
return acc;
}, []);
res.push(...newNodesCopy);
return res;
};
const __default__$3 = defineComponent({
name: "ElCascaderPanel"
});
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
...__default__$3,
props: cascaderPanelProps,
emits: cascaderPanelEmits,
setup(__props, { expose, emit }) {
const props = __props;
let manualChecked = false;
const ns = useNamespace("cascader");
const config = useCascaderConfig(props);
const slots = useSlots();
let store;
const initialLoaded = ref(true);
const initialLoadedOnce = ref(false);
const menuList = ref([]);
const checkedValue = ref();
const menus = ref([]);
const expandingNode = ref();
const checkedNodes = ref([]);
const isHoverMenu = computed(() => config.value.expandTrigger === "hover");
const renderLabelFn = computed(() => props.renderLabel || slots.default);
const initStore = () => {
const { options } = props;
const cfg = config.value;
manualChecked = false;
store = new Store(options, cfg);
menus.value = [store.getNodes()];
if (cfg.lazy && isEmpty(props.options)) {
initialLoaded.value = false;
lazyLoad(void 0, (list) => {
if (list) {
store = new Store(list, cfg);
menus.value = [store.getNodes()];
}
initialLoaded.value = true;
syncCheckedValue(false, true);
});
} else {
syncCheckedValue(false, true);
}
};
const lazyLoad = (node, cb) => {
const cfg = config.value;
node = node || new Node$1({}, cfg, void 0, true);
node.loading = true;
const resolve = (dataList) => {
const _node = node;
const parent = _node.root ? null : _node;
_node.loading = false;
_node.loaded = true;
_node.childrenData = _node.childrenData || [];
dataList && (store == null ? void 0 : store.appendNodes(dataList, parent));
dataList && (cb == null ? void 0 : cb(dataList));
if (node.level === 0) {
initialLoadedOnce.value = true;
}
};
const reject = () => {
node.loading = false;
node.loaded = false;
if (node.level === 0) {
initialLoaded.value = true;
}
};
cfg.lazyLoad(node, resolve, reject);
};
const expandNode = (node, silent) => {
var _a;
const { level } = node;
const newMenus = menus.value.slice(0, level);
let newExpandingNode;
if (node.isLeaf) {
newExpandingNode = node.pathNodes[level - 2];
} else {
newExpandingNode = node;
newMenus.push(node.children);
}
if (((_a = expandingNode.value) == null ? void 0 : _a.uid) !== (newExpandingNode == null ? void 0 : newExpandingNode.uid)) {
expandingNode.value = node;
menus.value = newMenus;
!silent && emit("expand-change", (node == null ? void 0 : node.pathValues) || []);
}
};
const handleCheckChange = (node, checked, emitClose = true) => {
const { checkStrictly, multiple } = config.value;
const oldNode = checkedNodes.value[0];
manualChecked = true;
!multiple && (oldNode == null ? void 0 : oldNode.doCheck(false));
node.doCheck(checked);
calculateCheckedValue();
emitClose && !multiple && !checkStrictly && emit("close");
!emitClose && !multiple && expandParentNode(node);
};
const expandParentNode = (node) => {
if (!node)
return;
node = node.parent;
expandParentNode(node);
node && expandNode(node);
};
const getFlattedNodes = (leafOnly) => store == null ? void 0 : store.getFlattedNodes(leafOnly);
const getCheckedNodes = (leafOnly) => {
var _a;
return (_a = getFlattedNodes(leafOnly)) == null ? void 0 : _a.filter(({ checked }) => checked !== false);
};
const clearCheckedNodes = () => {
checkedNodes.value.forEach((node) => node.doCheck(false));
calculateCheckedValue();
menus.value = menus.value.slice(0, 1);
expandingNode.value = void 0;
emit("expand-change", []);
};
const calculateCheckedValue = () => {
var _a;
const { checkStrictly, multiple } = config.value;
const oldNodes = checkedNodes.value;
const newNodes = getCheckedNodes(!checkStrictly);
const nodes = sortByOriginalOrder(oldNodes, newNodes);
const values = nodes.map((node) => node.valueByOption);
checkedNodes.value = nodes;
checkedValue.value = multiple ? values : (_a = values[0]) != null ? _a : null;
};
const syncCheckedValue = (loaded = false, forced = false) => {
const { modelValue } = props;
const { lazy, multiple, checkStrictly } = config.value;
const leafOnly = !checkStrictly;
if (!initialLoaded.value || manualChecked || !forced && isEqual(modelValue, checkedValue.value))
return;
if (lazy && !loaded) {
const values = unique(flattenDeep(castArray(modelValue)));
const nodes = values.map((val) => store == null ? void 0 : store.getNodeByValue(val)).filter((node) => !!node && !node.loaded && !node.loading);
if (nodes.length) {
nodes.forEach((node) => {
lazyLoad(node, () => syncCheckedValue(false, forced));
});
} else {
syncCheckedValue(true, forced);
}
} else {
const values = multiple ? castArray(modelValue) : [modelValue];
const nodes = unique(values.map((val) => store == null ? void 0 : store.getNodeByValue(val, leafOnly)));
syncMenuState(nodes, forced);
checkedValue.value = cloneDeep(modelValue != null ? modelValue : void 0);
}
};
const syncMenuState = (newCheckedNodes, reserveExpandingState = true) => {
const { checkStrictly } = config.value;
const oldNodes = checkedNodes.value;
const newNodes = newCheckedNodes.filter((node) => !!node && (checkStrictly || node.isLeaf));
const oldExpandingNode = store == null ? void 0 : store.getSameNode(expandingNode.value);
const newExpandingNode = reserveExpandingState && oldExpandingNode || newNodes[0];
if (newExpandingNode) {
newExpandingNode.pathNodes.forEach((node) => expandNode(node, true));
} else {
expandingNode.value = void 0;
}
oldNodes.forEach((node) => node.doCheck(false));
reactive(newNodes).forEach((node) => node.doCheck(true));
checkedNodes.value = newNodes;
nextTick(scrollToExpandingNode);
};
const scrollToExpandingNode = () => {
if (!isClient)
return;
menuList.value.forEach((menu) => {
const menuElement = menu == null ? void 0 : menu.$el;
if (menuElement) {
const container = menuElement.querySelector(`.${ns.namespace.value}-scrollbar__wrap`);
const activeNode = menuElement.querySelector(`.${ns.b("node")}.${ns.is("active")}:last-child`) || menuElement.querySelector(`.${ns.b("node")}.in-active-path`);
scrollIntoView(container, activeNode);
}
});
};
const handleKeyDown = (e) => {
const target = e.target;
const code = getEventCode(e);
switch (code) {
case EVENT_CODE.up:
case EVENT_CODE.down: {
e.preventDefault();
const distance = code === EVENT_CODE.up ? -1 : 1;
focusNode(getSibling(target, distance, `.${ns.b("node")}[tabindex="-1"]`));
break;
}
case EVENT_CODE.left: {
e.preventDefault();
const preMenu = menuList.value[getMenuIndex(target) - 1];
const expandedNode = preMenu == null ? void 0 : preMenu.$el.querySelector(`.${ns.b("node")}[aria-expanded="true"]`);
focusNode(expandedNode);
break;
}
case EVENT_CODE.right: {
e.preventDefault();
const nextMenu = menuList.value[getMenuIndex(target) + 1];
const firstNode = nextMenu == null ? void 0 : nextMenu.$el.querySelector(`.${ns.b("node")}[tabindex="-1"]`);
focusNode(firstNode);
break;
}
case EVENT_CODE.enter:
case EVENT_CODE.numpadEnter:
checkNode(target);
break;
}
};
provide(CASCADER_PANEL_INJECTION_KEY, reactive({
config,
expandingNode,
checkedNodes,
isHoverMenu,
initialLoaded,
renderLabelFn,
lazyLoad,
expandNode,
handleCheckChange
}));
watch(config, (newVal, oldVal) => {
if (isEqual(newVal, oldVal))
return;
initStore();
}, {
immediate: true
});
watch(() => props.options, initStore, {
deep: true
});
watch(() => props.modelValue, () => {
manualChecked = false;
syncCheckedValue();
}, {
deep: true
});
watch(() => checkedValue.value, (val) => {
if (!isEqual(val, props.modelValue)) {
emit(UPDATE_MODEL_EVENT, val);
emit(CHANGE_EVENT, val);
}
});
const loadLazyRootNodes = () => {
if (initialLoadedOnce.value)
return;
initStore();
};
onBeforeUpdate(() => menuList.value = []);
onMounted(() => !isEmpty(props.modelValue) && syncCheckedValue());
expose({
menuList,
menus,
checkedNodes,
handleKeyDown,
handleCheckChange,
getFlattedNodes,
getCheckedNodes,
clearCheckedNodes,
calculateCheckedValue,
scrollToExpandingNode,
loadLazyRootNodes
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: normalizeClass([unref(ns).b("panel"), unref(ns).is("bordered", _ctx.border)]),
onKeydown: handleKeyDown
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(menus.value, (menu, index) => {
return openBlock(), createBlock(ElCascaderMenu, {
key: index,
ref_for: true,
ref: (item) => menuList.value[index] = item,
index,
nodes: [...menu]
}, {
empty: withCtx(() => [
renderSlot(_ctx.$slots, "empty")
]),
_: 2
}, 1032, ["index", "nodes"]);
}), 128))
], 34);
};
}
});
var CascaderPanel = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__file", "index.vue"]]);
const ElCascaderPanel = withInstall(CascaderPanel);
const cascaderProps = buildProps({
...CommonProps,
size: useSizeProp,
placeholder: String,
disabled: Boolean,
clearable: Boolean,
clearIcon: {
type: iconPropType,
default: CircleClose
},
filterable: Boolean,
filterMethod: {
type: definePropType(Function),
default: (node, keyword) => node.text.includes(keyword)
},
separator: {
type: String,
default: " / "
},
showAllLevels: {
type: Boolean,
default: true
},
collapseTags: Boolean,
maxCollapseTags: {
type: Number,
default: 1
},
collapseTagsTooltip: Boolean,
maxCollapseTagsTooltipHeight: {
type: [String, Number]
},
debounce: {
type: Number,
default: 300
},
beforeFilter: {
type: definePropType(Function),
default: () => true
},
placement: {
type: definePropType(String),
values: Ee,
default: "bottom-start"
},
fallbackPlacements: {
type: definePropType(Array),
default: ["bottom-start", "bottom", "top-start", "top", "right", "left"]
},
popperClass: useTooltipContentProps.popperClass,
popperStyle: useTooltipContentProps.popperStyle,
teleported: useTooltipContentProps.teleported,
effect: {
type: definePropType(String),
default: "light"
},
tagType: { ...tagProps.type, default: "info" },
tagEffect: { ...tagProps.effect, default: "light" },
validateEvent: {
type: Boolean,
default: true
},
persistent: {
type: Boolean,
default: true
},
showCheckedStrategy: {
type: String,
values: ["parent", "child"],
default: "child"
},
checkOnClickNode: Boolean,
showPrefix: {
type: Boolean,
default: true
},
...useEmptyValuesProps
});
const emitChangeFn = (value) => true;
const cascaderEmits = {
[UPDATE_MODEL_EVENT]: emitChangeFn,
[CHANGE_EVENT]: emitChangeFn,
focus: (evt) => evt instanceof FocusEvent,
blur: (evt) => evt instanceof FocusEvent,
clear: () => true,
visibleChange: (val) => isBoolean(val),
expandChange: (val) => !!val,
removeTag: (val) => !!val
};
const __default__$2 = defineComponent({
name: "ElCascader"
});
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
...__default__$2,
props: cascaderProps,
emits: cascaderEmits,
setup(__props, { expose, emit }) {
const props = __props;
const popperOptions = {
modifiers: [
{
name: "arrowPosition",
enabled: true,
phase: "main",
fn: ({ state }) => {
const { modifiersData, placement } = state;
if (["right", "left", "bottom", "top"].includes(placement))
return;
if (modifiersData.arrow) {
modifiersData.arrow.x = 35;
}
},
requires: ["arrow"]
}
]
};
const attrs = useAttrs();
let inputInitialHeight = 0;
let pressDeleteCount = 0;
const nsCascader = useNamespace("cascader");
const nsInput = useNamespace("input");
const { t } = useLocale();
const { formItem } = useFormItem();
const isDisabled = useFormDisabled();
const { valueOnClear } = useEmptyValues(props);
const { isComposing, handleComposition } = useComposition({
afterComposition(event) {
var _a;
const text = (_a = event.target) == null ? void 0 : _a.value;
handleInput(text);
}
});
const tooltipRef = ref();
const tagTooltipRef = ref();
const inputRef = ref();
const tagWrapper = ref();
const cascaderPanelRef = ref();
const suggestionPanel = ref();
const popperVisible = ref(false);
const inputHover = ref(false);
const filtering = ref(false);
const inputValue = ref("");
const searchInputValue = ref("");
const tags = ref([]);
const suggestions = ref([]);
const showTagList = computed(() => {
if (!props.props.multiple) {
return [];
}
return props.collapseTags ? tags.value.slice(0, props.maxCollapseTags) : tags.value;
});
const collapseTagList = computed(() => {
if (!props.props.multiple) {
return [];
}
return props.collapseTags ? tags.value.slice(props.maxCollapseTags) : [];
});
const cascaderStyle = computed(() => {
return attrs.style;
});
const inputPlaceholder = computed(() => {
var _a;
return (_a = props.placeholder) != null ? _a : t("el.cascader.placeholder");
});
const currentPlaceholder = computed(() => searchInputValue.value || tags.value.length > 0 || isComposing.value ? "" : inputPlaceholder.value);
const realSize = useFormSize();
const tagSize = computed(() => realSize.value === "small" ? "small" : "default");
const multiple = computed(() => !!props.props.multiple);
const readonly = computed(() => !props.filterable || multiple.value);
const searchKeyword = computed(() => multiple.value ? searchInputValue.value : inputValue.value);
const checkedNodes = computed(() => {
var _a;
return ((_a = cascaderPanelRef.value) == null ? void 0 : _a.checkedNodes) || [];
});
const { wrapperRef, isFocused, handleBlur } = useFocusController(inputRef, {
disabled: isDisabled,
beforeBlur(event) {
var _a, _b;
return ((_a = tooltipRef.value) == null ? void 0 : _a.isFocusInsideContent(event)) || ((_b = tagTooltipRef.value) == null ? void 0 : _b.isFocusInsideContent(event));
},
afterBlur() {
var _a;
if (props.validateEvent) {
(_a = formItem == null ? void 0 : formItem.validate) == null ? void 0 : _a.call(formItem, "blur").catch((err) => debugWarn(err));
}
}
});
const clearBtnVisible = computed(() => {
if (!props.clearable || isDisabled.value || filtering.value || !inputHover.value && !isFocused.value)
return false;
return !!checkedNodes.value.length;
});
const presentText = computed(() => {
const { showAllLevels, separator } = props;
const nodes = checkedNodes.value;
return nodes.length ? multiple.value ? "" : nodes[0].calcText(showAllLevels, separator) : "";
});
const validateState = computed(() => (formItem == null ? void 0 : formItem.validateState) || "");
const checkedValue = computed({
get() {
return cloneDeep(props.modelValue);
},
set(val) {
const value = val != null ? val : valueOnClear.value;
emit(UPDATE_MODEL_EVENT, value);
emit(CHANGE_EVENT, value);
if (props.validateEvent) {
formItem == null ? void 0 : formItem.validate("change").catch((err) => debugWarn(err));
}
}
});
const cascaderKls = computed(() => {
return [
nsCascader.b(),
nsCascader.m(realSize.value),
nsCascader.is("disabled", isDisabled.value),
attrs.class
];
});
const cascaderIconKls = computed(() => {
return [
nsInput.e("icon"),
"icon-arrow-down",
nsCascader.is("reverse", popperVisible.value)
];
});
const inputClass = computed(() => nsCascader.is("focus", isFocused.value));
const contentRef = computed(() => {
var _a, _b;
return (_b = (_a = tooltipRef.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef;
});
const handleClickOutside = (event) => {
if (isFocused.value) {
const _event = new FocusEvent("blur", event);
handleBlur(_event);
}
togglePopperVisible(false);
};
const togglePopperVisible = (visible) => {
var _a, _b, _c;
if (isDisabled.value)
return;
visible = visible != null ? visible : !popperVisible.value;
if (visible !== popperVisible.value) {
popperVisible.value = visible;
(_b = (_a = inputRef.value) == null ? void 0 : _a.input) == null ? void 0 : _b.setAttribute("aria-expanded", `${visible}`);
if (visible) {
updatePopperPosition();
nextTick((_c = cascaderPanelRef.value) == null ? void 0 : _c.scrollToExpandingNode);
} else if (props.filterable) {
syncPresentTextValue();
}
emit("visibleChange", visible);
}
};
const updatePopperPosition = () => {
nextTick(() => {
var _a;
(_a = tooltipRef.value) == null ? void 0 : _a.updatePopper();
});
};
const hideSuggestionPanel = () => {
filtering.value = false;
};
const genTag = (node) => {
const { showAllLevels, separator } = props;
return {
node,
key: node.uid,
text: node.calcText(showAllLevels, separator),
hitState: false,
closable: !isDisabled.value && !node.isDisabled
};
};
const deleteTag = (tag) => {
var _a;
const node = tag.node;
node.doCheck(false);
(_a = cascaderPanelRef.value) == null ? void 0 : _a.calculateCheckedValue();
emit("removeTag", node.valueByOption);
};
const getStrategyCheckedNodes = () => {
switch (props.showCheckedStrategy) {
case "child":
return checkedNodes.value;
case "parent": {
const clickedNodes = getCheckedNodes(false);
const clickedNodesValue = clickedNodes.map((o) => o.value);
const parentNodes = clickedNodes.filter((o) => !o.parent || !clickedNodesValue.includes(o.parent.value));
return parentNodes;
}
default:
return [];
}
};
const calculatePresentTags = () => {
if (!multiple.value)
return;
const nodes = getStrategyCheckedNodes();
const allTags = [];
nodes.forEach((node) => allTags.push(genTag(node)));
tags.value = allTags;
};
const calculateSuggestions = () => {
var _a, _b;
const { filterMethod, showAllLevels, separator } = props;
const res = (_b = (_a = cascaderPanelRef.value) == null ? void 0 : _a.getFlattedNodes(!props.props.checkStrictly)) == null ? void 0 : _b.filter((node) => {
if (node.isDisabled)
return false;
node.calcText(showAllLevels, separator);
return filterMethod(node, searchKeyword.value);
});
if (multiple.value) {
tags.value.forEach((tag) => {
tag.hitState = false;
});
}
filtering.value = true;
suggestions.value = res;
updatePopperPosition();
};
const focusFirstNode = () => {
var _a;
let firstNode;
if (filtering.value && suggestionPanel.value) {
firstNode = suggestionPanel.value.$el.querySelector(`.${nsCascader.e("suggestion-item")}`);
} else {
firstNode = (_a = cascaderPanelRef.value) == null ? void 0 : _a.$el.querySelector(`.${nsCascader.b("node")}[tabindex="-1"]`);
}
if (firstNode) {
firstNode.focus();
!filtering.value && firstNode.click();
}
};
const updateStyle = () => {
var _a, _b;
const inputInner = (_a = inputRef.value) == null ? void 0 : _a.input;
const tagWrapperEl = tagWrapper.value;
const suggestionPanelEl = (_b = suggestionPanel.value) == null ? void 0 : _b.$el;
if (!isClient || !inputInner)
return;
if (suggestionPanelEl) {
const suggestionList = suggestionPanelEl.querySelector(`.${nsCascader.e("suggestion-list")}`);
suggestionList.style.minWidth = `${inputInner.offsetWidth}px`;
}
if (tagWrapperEl) {
const { offsetHeight } = tagWrapperEl;
const height = tags.value.length > 0 ? `${Math.max(offsetHeight, inputInitialHeight) - 2}px` : `${inputInitialHeight}px`;
inputInner.style.height = height;
updatePopperPosition();
}
};
const getCheckedNodes = (leafOnly) => {
var _a;
return (_a = cascaderPanelRef.value) == null ? void 0 : _a.getCheckedNodes(leafOnly);
};
const handleExpandChange = (value) => {
updatePopperPosition();
emit("expandChange", value);
};
const handleKeyDown = (e) => {
if (isComposing.value)
return;
const code = getEventCode(e);
switch (code) {
case EVENT_CODE.enter:
case EVENT_CODE.numpadEnter:
togglePopperVisible();
break;
case EVENT_CODE.down:
togglePopperVisible(true);
nextTick(focusFirstNode);
e.preventDefault();
break;
case EVENT_CODE.esc:
if (popperVisible.value === true) {
e.preventDefault();
e.stopPropagation();
togglePopperVisible(false);
}
break;
case EVENT_CODE.tab:
togglePopperVisible(false);
break;
}
};
const handleClear = () => {
var _a;
(_a = cascaderPanelRef.value) == null ? void 0 : _a.clearCheckedNodes();
if (!popperVisible.value && props.filterable) {
syncPresentTextValue();
}
togglePopperVisible(false);
emit("clear");
};
const syncPresentTextValue = () => {
const { value } = presentText;
inputValue.value = value;
searchInputValue.value = value;
};
const handleSuggestionClick = (node) => {
var _a, _b;
const { checked } = node;
if (multiple.value) {
(_a = cascaderPanelRef.value) == null ? void 0 : _a.handleCheckChange(node, !checked, false);
} else {
!checked && ((_b = cascaderPanelRef.value) == null ? void 0 : _b.handleCheckChange(node, true, false));
togglePopperVisible(false);
}
};
const handleSuggestionKeyDown = (e) => {
const target = e.target;
const code = getEventCode(e);
switch (code) {
case EVENT_CODE.up:
case EVENT_CODE.down: {
e.preventDefault();
const distance = code === EVENT_CODE.up ? -1 : 1;
focusNode(getSibling(target, distance, `.${nsCascader.e("suggestion-item")}[tabindex="-1"]`));
break;
}
case EVENT_CODE.enter:
case EVENT_CODE.numpadEnter:
target.click();
break;
}
};
const handleDelete = () => {
const lastTag = tags.value[tags.value.length - 1];
pressDeleteCount = searchInputValue.value ? 0 : pressDeleteCount + 1;
if (!lastTag || !pressDeleteCount || props.collapseTags && tags.value.length > 1)
return;
if (lastTag.hitState) {
deleteTag(lastTag);
} else {
lastTag.hitState = true;
}
};
const debounce = computed(() => props.debounce);
const handleFilter = useDebounceFn(() => {
const { value } = searchKeyword;
if (!value)
return;
const passed = props.beforeFilter(value);
if (isPromise(passed)) {
passed.then(calculateSuggestions).catch(() => {
});
} else if (passed !== false) {
calculateSuggestions();
} else {
hideSuggestionPanel();
}
}, debounce);
const handleInput = (val, e) => {
!popperVisible.value && togglePopperVisible(true);
if (e == null ? void 0 : e.isComposing)
return;
val ? handleFilter() : hideSuggestionPanel();
};
const getInputInnerHeight = (inputInner) => Number.parseFloat(useCssVar(nsInput.cssVarName("input-height"), inputInner).value) - 2;
const focus = () => {
var _a;
(_a = inputRef.value) == null ? void 0 : _a.focus();
};
const blur = () => {
var _a;
(_a = inputRef.value) == null ? void 0 : _a.blur();
};
watch(filtering, updatePopperPosition);
watch([
checkedNodes,
isDisabled,
() => props.collapseTags,
() => props.maxCollapseTags
], calculatePresentTags);
watch(tags, () => {
nextTick(() => updateStyle());
});
watch(realSize, async () => {
await nextTick();
const inputInner = inputRef.value.input;
inputInitialHeight = getInputInnerHeight(inputInner) || inputInitialHeight;
updateStyle();
});
watch(presentText, syncPresentTextValue, { immediate: true });
watch(() => popperVisible.value, (val) => {
var _a;
if (val && props.props.lazy && props.props.lazyLoad) {
(_a = cascaderPanelRef.value) == null ? void 0 : _a.loadLazyRootNodes();
}
});
onMounted(() => {
const inputInner = inputRef.value.input;
const inputInnerHeight = getInputInnerHeight(inputInner);
inputInitialHeight = inputInner.offsetHeight || inputInnerHeight;
useResizeObserver(inputInner, updateStyle);
});
expose({
getCheckedNodes,
cascaderPanelRef,
togglePopperVisible,
contentRef,
presentText,
focus,
blur
});
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(ElTooltip), {
ref_key: "tooltipRef",
ref: tooltipRef,
visible: popperVisible.value,
teleported: _ctx.teleported,
"popper-class": [unref(nsCascader).e("dropdown"), _ctx.popperClass],
"popper-style": _ctx.popperStyle,
"popper-options": popperOptions,
"fallback-p