mldong-flow-designer-plus
Version:
本项目包含了作者为B站课堂视频[《工作流设计器开发最佳实践》](https://www.bilibili.com/cheese/play/ss24484)的过程源码。教程中开发的组件也可用于实际生产环境中。以下是和使用文档和课程章节说明。 ## 实战项目 [演示地址](https://flow-pro.mldong.com/)
1,478 lines • 93.2 kB
JavaScript
import { k as isArray, a as buildProps, F as throwError, t as isObject, L as useNamespace, p as isFocusable, s as isNumber, g as definePropType, m as isClient, f as debugWarn, P as withInstall, n as isElement, N as NOOP, o as isEmpty, z as isUndefined, q as isFunction, v as isPlainObject, J as useDebounceFn, r as isIOS, x as isString, R as withNoopInstall } from "./error-DEV4o0cD.js";
import { _ as _plugin_vue_export_helper_default } from "./index-Bjjqy_0d.js";
import { u as useId } from "./index-D7GCrely.js";
import { isVNode, inject, computed, getCurrentInstance, toRaw, watch, defineComponent, unref, reactive, toRefs, onBeforeUnmount, nextTick, withDirectives, openBlock, createElementBlock, withModifiers, normalizeClass, renderSlot, createElementVNode, toDisplayString, vShow, ref, provide, onMounted, shallowRef, toRef, createBlock, Transition, withCtx, normalizeStyle, Fragment, createVNode, onActivated, onUpdated, resolveDynamicComponent, createCommentVNode, useSlots, watchEffect, resolveComponent, resolveDirective, mergeProps, toHandlerKey, renderList, createTextVNode } from "vue";
import { c as castArray, j as get, m as isEqual, n as isNil, d as clamp, h as findLastIndex } from "./index-C41_Bymr.js";
import { C as CHANGE_EVENT, U as UPDATE_MODEL_EVENT } from "./event-BZTOGHfp.js";
import { b as arrow_down_default, i as iconPropType, c as circle_close_default, E as ElIcon, d as close_default, V as ValidateComponentsMap } from "./index-D0I3i9fl.js";
import { c as componentSizes, d as useSizeProp, b as addUnit } from "./style-D2s_cWsv.js";
import { a as useEmptyValuesProps, b as useLocale, u as useEmptyValues } from "./index-BbcOBREW.js";
import { u as useAriaProps } from "./index-E3-NBeOi.js";
import { u as useTooltipContentProps, E as Ee, a as ElTooltip } from "./index-ChSanhjG.js";
import { b as useMutationObserver, c as useResizeObserver, a as useEventListener } from "./index-rPPo0srK.js";
import { c as useFormSize, a as useFormItem, b as useFormItemInputId, u as useFormDisabled } from "./use-form-item-DkmO9Upg.js";
import { g as getEventCode, E as EVENT_CODE } from "./event-bJhzntMi.js";
import { s as scrollIntoView } from "./scroll-CYVj_8on.js";
import { u as useComposition, a as useFocusController } from "./index-D5q4e_u4.js";
const escapeStringRegexp = (string = "") => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
const flattedChildren = (children) => {
const vNodes = isArray(children) ? children : [children];
const result = [];
vNodes.forEach((child) => {
var _a;
if (isArray(child)) result.push(...flattedChildren(child));
else if (isVNode(child) && ((_a = child.component) == null ? void 0 : _a.subTree)) result.push(child, ...flattedChildren(child.component.subTree));
else if (isVNode(child) && isArray(child.children)) result.push(...flattedChildren(child.children));
else if (isVNode(child) && child.shapeFlag === 2) result.push(...flattedChildren(child.type()));
else result.push(child);
});
return result;
};
const selectGroupKey = Symbol("ElSelectGroup");
const selectKey = Symbol("ElSelect");
const COMPONENT_NAME$3 = "ElOption";
const optionProps = buildProps({
/**
* @description value of option
*/
value: {
type: [
String,
Number,
Boolean,
Object
],
required: true
},
/**
* @description label of option, same as `value` if omitted
*/
label: { type: [String, Number] },
created: Boolean,
/**
* @description whether option is disabled
*/
disabled: Boolean
});
function useOption(props, states) {
const select = inject(selectKey);
if (!select) throwError(COMPONENT_NAME$3, "usage: <el-select><el-option /></el-select/>");
const selectGroup = inject(selectGroupKey, { disabled: false });
const itemSelected = computed(() => {
return contains(castArray(select.props.modelValue), props.value);
});
const limitReached = computed(() => {
if (select.props.multiple) {
const modelValue = castArray(select.props.modelValue ?? []);
return !itemSelected.value && modelValue.length >= select.props.multipleLimit && select.props.multipleLimit > 0;
} else return false;
});
const currentLabel = computed(() => {
return props.label ?? (isObject(props.value) ? "" : props.value);
});
const currentValue = computed(() => {
return props.value || props.label || "";
});
const isDisabled = computed(() => {
return props.disabled || states.groupDisabled || limitReached.value;
});
const instance = getCurrentInstance();
const contains = (arr = [], target) => {
if (!isObject(props.value)) return arr && arr.includes(target);
else {
const valueKey = select.props.valueKey;
return arr && arr.some((item) => {
return toRaw(get(item, valueKey)) === get(target, valueKey);
});
}
};
const hoverItem = () => {
if (!isDisabled.value) select.states.hoveringIndex = select.optionsArray.indexOf(instance.proxy);
};
const updateOption = (query) => {
states.visible = new RegExp(escapeStringRegexp(query), "i").test(String(currentLabel.value)) || props.created;
};
watch(() => currentLabel.value, () => {
if (!props.created && !select.props.remote) select.setSelected();
});
watch(() => props.value, (val, oldVal) => {
const { remote, valueKey } = select.props;
if (remote ? val !== oldVal : !isEqual(val, oldVal)) {
select.onOptionDestroy(oldVal, instance.proxy);
select.onOptionCreate(instance.proxy);
}
if (!props.created && !remote) {
if (valueKey && isObject(val) && isObject(oldVal) && val[valueKey] === oldVal[valueKey]) return;
select.setSelected();
}
});
watch(() => selectGroup.disabled, () => {
states.groupDisabled = selectGroup.disabled;
}, { immediate: true });
return {
select,
currentLabel,
currentValue,
itemSelected,
isDisabled,
hoverItem,
updateOption
};
}
var option_vue_vue_type_script_lang_default = defineComponent({
name: COMPONENT_NAME$3,
componentName: COMPONENT_NAME$3,
props: optionProps,
setup(props) {
const ns = useNamespace("select");
const id = useId();
const containerKls = computed(() => [
ns.be("dropdown", "item"),
ns.is("disabled", unref(isDisabled)),
ns.is("selected", unref(itemSelected)),
ns.is("hovering", unref(hover))
]);
const states = reactive({
index: -1,
groupDisabled: false,
visible: true,
hover: false
});
const { currentLabel, itemSelected, isDisabled, select, hoverItem, updateOption } = useOption(props, states);
const { visible, hover } = toRefs(states);
const vm = getCurrentInstance().proxy;
select.onOptionCreate(vm);
onBeforeUnmount(() => {
const key = vm.value;
nextTick(() => {
const { selected: selectedOptions } = select.states;
const doesSelected = selectedOptions.some((item) => {
return item.value === vm.value;
});
if (select.states.cachedOptions.get(key) === vm && !doesSelected) select.states.cachedOptions.delete(key);
});
select.onOptionDestroy(key, vm);
});
function selectOptionClick() {
if (!isDisabled.value) select.handleOptionSelect(vm);
}
const handleMousedown = (event) => {
let target = event.target;
const currentTarget = event.currentTarget;
while (target && target !== currentTarget) {
if (isFocusable(target)) return;
target = target.parentElement;
}
event.preventDefault();
};
return {
ns,
id,
containerKls,
currentLabel,
itemSelected,
isDisabled,
select,
visible,
hover,
states,
hoverItem,
handleMousedown,
updateOption,
selectOptionClick
};
}
});
const _hoisted_1$3 = [
"id",
"aria-disabled",
"aria-selected"
];
function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
return withDirectives((openBlock(), createElementBlock("li", {
id: _ctx.id,
class: normalizeClass(_ctx.containerKls),
role: "option",
"aria-disabled": _ctx.isDisabled || void 0,
"aria-selected": _ctx.itemSelected,
onMousemove: _cache[0] || (_cache[0] = (...args) => _ctx.hoverItem && _ctx.hoverItem(...args)),
onMousedown: _cache[1] || (_cache[1] = (...args) => _ctx.handleMousedown && _ctx.handleMousedown(...args)),
onClick: _cache[2] || (_cache[2] = withModifiers((...args) => _ctx.selectOptionClick && _ctx.selectOptionClick(...args), ["stop"]))
}, [renderSlot(_ctx.$slots, "default", {}, () => [createElementVNode("span", null, toDisplayString(_ctx.currentLabel), 1)])], 42, _hoisted_1$3)), [[vShow, _ctx.visible]]);
}
var option_default = /* @__PURE__ */ _plugin_vue_export_helper_default(option_vue_vue_type_script_lang_default, [["render", _sfc_render$3]]);
const scrollbarProps = buildProps({
/**
* @description trigger distance(px)
*/
distance: {
type: Number,
default: 0
},
/**
* @description height of scrollbar
*/
height: {
type: [String, Number],
default: ""
},
/**
* @description max height of scrollbar
*/
maxHeight: {
type: [String, Number],
default: ""
},
/**
* @description whether to use the native scrollbar
*/
native: Boolean,
/**
* @description style of wrap
*/
wrapStyle: {
type: definePropType([
String,
Object,
Array,
Boolean
]),
default: ""
},
/**
* @description class of wrap
*/
wrapClass: {
type: [String, Array],
default: ""
},
/**
* @description class of view
*/
viewClass: {
type: [String, Array],
default: ""
},
/**
* @description style of view
*/
viewStyle: {
type: definePropType([
String,
Object,
Array,
Boolean
]),
default: ""
},
/**
* @description do not respond to container size changes, if the container size does not change, it is better to set it to optimize performance
*/
noresize: Boolean,
/**
* @description element tag of the view
*/
tag: {
type: String,
default: "div"
},
/**
* @description always show
*/
always: Boolean,
/**
* @description minimum size of scrollbar
*/
minSize: {
type: Number,
default: 20
},
/**
* @description Wrap tabindex
*/
tabindex: {
type: [String, Number],
default: void 0
},
/**
* @description id of view
*/
id: String,
/**
* @description role of view
*/
role: String,
...useAriaProps(["ariaLabel", "ariaOrientation"])
});
const scrollbarEmits = {
"end-reached": (direction) => [
"left",
"right",
"top",
"bottom"
].includes(direction),
scroll: ({ scrollTop, scrollLeft }) => [scrollTop, scrollLeft].every(isNumber)
};
const tagProps = buildProps({
/**
* @description type of Tag
*/
type: {
type: String,
values: [
"primary",
"success",
"info",
"warning",
"danger"
],
default: "primary"
},
/**
* @description whether Tag can be removed
*/
closable: Boolean,
/**
* @description whether to disable animations
*/
disableTransitions: Boolean,
/**
* @description whether Tag has a highlighted border
*/
hit: Boolean,
/**
* @description background color of the Tag
*/
color: String,
/**
* @description size of Tag
*/
size: {
type: String,
values: componentSizes
},
/**
* @description theme of Tag
*/
effect: {
type: String,
values: [
"dark",
"light",
"plain"
],
default: "light"
},
/**
* @description whether Tag is rounded
*/
round: Boolean
});
const tagEmits = {
close: (evt) => evt instanceof MouseEvent,
click: (evt) => evt instanceof MouseEvent
};
const defaultProps = {
label: "label",
value: "value",
disabled: "disabled",
options: "options"
};
function useProps(props) {
const aliasProps = ref({
...defaultProps,
...props.props
});
let cache = { ...props.props };
watch(() => props.props, (val) => {
if (!isEqual(val, cache)) {
aliasProps.value = {
...defaultProps,
...val
};
cache = { ...val };
}
}, { deep: true });
const getLabel = (option) => get(option, aliasProps.value.label);
const getValue = (option) => get(option, aliasProps.value.value);
const getDisabled = (option) => get(option, aliasProps.value.disabled);
const getOptions = (option) => get(option, aliasProps.value.options);
return {
aliasProps,
getLabel,
getValue,
getDisabled,
getOptions
};
}
const selectProps = buildProps({
/**
* @description the name attribute of select input
*/
name: String,
/**
* @description native input id
*/
id: String,
/**
* @description binding value
*/
modelValue: {
type: definePropType([
Array,
String,
Number,
Boolean,
Object
]),
default: void 0
},
/**
* @description the autocomplete attribute of select input
*/
autocomplete: {
type: String,
default: "off"
},
/**
* @description for non-filterable Select, this prop decides if the option menu pops up when the input is focused
*/
automaticDropdown: Boolean,
/**
* @description size of Input
*/
size: useSizeProp,
/**
* @description tooltip theme, built-in theme: `dark` / `light`
*/
effect: {
type: definePropType(String),
default: "light"
},
/**
* @description whether Select is disabled
*/
disabled: {
type: Boolean,
default: void 0
},
/**
* @description whether select can be cleared
*/
clearable: Boolean,
/**
* @description whether Select is filterable
*/
filterable: Boolean,
/**
* @description whether creating new items is allowed. To use this, `filterable` must be true
*/
allowCreate: Boolean,
/**
* @description whether Select is loading data from server
*/
loading: Boolean,
/**
* @description custom class name for Select's dropdown
*/
popperClass: {
type: String,
default: ""
},
/**
* @description custom style for Select's dropdown
*/
popperStyle: { type: definePropType([String, Object]) },
/**
* @description [popper.js](https://popper.js.org/docs/v2/) parameters
*/
popperOptions: {
type: definePropType(Object),
default: () => ({})
},
/**
* @description whether options are loaded from server
*/
remote: Boolean,
/**
* @description debounce delay during remote search, in milliseconds
*/
debounce: {
type: Number,
default: 300
},
/**
* @description displayed text while loading data from server, default is 'Loading'
*/
loadingText: String,
/**
* @description displayed text when no data matches the filtering query, you can also use slot `empty`, default is 'No matching data'
*/
noMatchText: String,
/**
* @description displayed text when there is no options, you can also use slot `empty`, default is 'No data'
*/
noDataText: String,
/**
* @description function that gets called when the input value changes. Its parameter is the current input value. To use this, `filterable` must be true
*/
remoteMethod: { type: definePropType(Function) },
/**
* @description custom filter method, the first parameter is the current input value. To use this, `filterable` must be true
*/
filterMethod: { type: definePropType(Function) },
/**
* @description whether multiple-select is activated
*/
multiple: Boolean,
/**
* @description maximum number of options user can select when `multiple` is `true`. No limit when set to 0
*/
multipleLimit: {
type: Number,
default: 0
},
/**
* @description placeholder, default is 'Select'
*/
placeholder: { type: String },
/**
* @description select first matching option on enter key. Use with `filterable` or `remote`
*/
defaultFirstOption: Boolean,
/**
* @description when `multiple` and `filter` is true, whether to reserve current keyword after selecting an option
*/
reserveKeyword: {
type: Boolean,
default: true
},
/**
* @description unique identity key name for value, required when value is an object
*/
valueKey: {
type: String,
default: "value"
},
/**
* @description whether to collapse tags to a text when multiple selecting
*/
collapseTags: Boolean,
/**
* @description whether show all selected tags when mouse hover text of collapse-tags. To use this, `collapse-tags` must be true
*/
collapseTagsTooltip: Boolean,
/**
* @description configuration object for the collapse-tags tooltip. To use this, `collapse-tags` and `collapse-tags-tooltip` must be true
*/
tagTooltip: {
type: definePropType(Object),
default: () => ({})
},
/**
* @description the max tags number to be shown. To use this, `collapse-tags` must be true
*/
maxCollapseTags: {
type: Number,
default: 1
},
/**
* @description whether select dropdown is teleported, if `true` it will be teleported to where `append-to` sets
*/
teleported: useTooltipContentProps.teleported,
/**
* @description when select dropdown is inactive and `persistent` is `false`, select dropdown will be destroyed
*/
persistent: {
type: Boolean,
default: true
},
/**
* @description custom clear icon component
*/
clearIcon: {
type: iconPropType,
default: circle_close_default
},
/**
* @description whether the width of the dropdown is the same as the input
*/
fitInputWidth: Boolean,
/**
* @description custom suffix icon component
*/
suffixIcon: {
type: iconPropType,
default: arrow_down_default
},
/**
* @description tag type
*/
tagType: {
...tagProps.type,
default: "info"
},
/**
* @description tag effect
*/
tagEffect: {
...tagProps.effect,
default: "light"
},
/**
* @description whether to trigger form validation
*/
validateEvent: {
type: Boolean,
default: true
},
/**
* @description in remote search method show suffix icon
*/
remoteShowSuffix: Boolean,
/**
* @description determines whether the arrow is displayed
*/
showArrow: {
type: Boolean,
default: true
},
/**
* @description offset of the dropdown
*/
offset: {
type: Number,
default: 12
},
/**
* @description position of dropdown
*/
placement: {
type: definePropType(String),
values: Ee,
default: "bottom-start"
},
/**
* @description list of possible positions for dropdown
*/
fallbackPlacements: {
type: definePropType(Array),
default: [
"bottom-start",
"top-start",
"right",
"left"
]
},
/**
* @description tabindex for input
*/
tabindex: {
type: [String, Number],
default: 0
},
/**
* @description which element the selection dropdown appends to
*/
appendTo: useTooltipContentProps.appendTo,
options: { type: definePropType(Array) },
props: {
type: definePropType(Object),
default: () => defaultProps
},
...useEmptyValuesProps,
...useAriaProps(["ariaLabel"])
});
const selectEmits = {
[UPDATE_MODEL_EVENT]: (val) => true,
[CHANGE_EVENT]: (val) => true,
"popup-scroll": scrollbarEmits.scroll,
"end-reached": scrollbarEmits["end-reached"],
"remove-tag": (val) => true,
"visible-change": (visible) => true,
focus: (evt) => evt instanceof FocusEvent,
blur: (evt) => evt instanceof FocusEvent,
clear: () => true
};
var option_group_vue_vue_type_script_lang_default = defineComponent({
name: "ElOptionGroup",
componentName: "ElOptionGroup",
props: {
/**
* @description name of the group
*/
label: String,
/**
* @description whether to disable all options in this group
*/
disabled: Boolean
},
setup(props) {
const ns = useNamespace("select");
const groupRef = ref();
const instance = getCurrentInstance();
const children = ref([]);
provide(selectGroupKey, reactive({ ...toRefs(props) }));
const visible = computed(() => children.value.some((option) => option.visible === true));
const isOption = (node) => {
var _a;
return node.type.name === "ElOption" && !!((_a = node.component) == null ? void 0 : _a.proxy);
};
const flattedChildren2 = (node) => {
const nodes = castArray(node);
const children2 = [];
nodes.forEach((child) => {
var _a;
if (!isVNode(child)) return;
if (isOption(child)) children2.push(child.component.proxy);
else if (isArray(child.children) && child.children.length) children2.push(...flattedChildren2(child.children));
else if ((_a = child.component) == null ? void 0 : _a.subTree) children2.push(...flattedChildren2(child.component.subTree));
});
return children2;
};
const updateChildren = () => {
children.value = flattedChildren2(instance.subTree);
};
onMounted(() => {
updateChildren();
});
useMutationObserver(groupRef, updateChildren, {
attributes: true,
subtree: true,
childList: true
});
return {
groupRef,
visible,
ns
};
}
});
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
return withDirectives((openBlock(), createElementBlock("ul", {
ref: "groupRef",
class: normalizeClass(_ctx.ns.be("group", "wrap"))
}, [createElementVNode("li", { class: normalizeClass(_ctx.ns.be("group", "title")) }, toDisplayString(_ctx.label), 3), createElementVNode("li", null, [createElementVNode("ul", { class: normalizeClass(_ctx.ns.b("group")) }, [renderSlot(_ctx.$slots, "default")], 2)])], 2)), [[vShow, _ctx.visible]]);
}
var option_group_default = /* @__PURE__ */ _plugin_vue_export_helper_default(option_group_vue_vue_type_script_lang_default, [["render", _sfc_render$2]]);
function useCalcInputWidth() {
const calculatorRef = shallowRef();
const calculatorWidth = ref(0);
const inputStyle = computed(() => ({ minWidth: `${Math.max(calculatorWidth.value, 11)}px` }));
const resetCalculatorWidth = () => {
var _a;
calculatorWidth.value = ((_a = calculatorRef.value) == null ? void 0 : _a.getBoundingClientRect().width) ?? 0;
};
useResizeObserver(calculatorRef, resetCalculatorWidth);
return {
calculatorRef,
calculatorWidth,
inputStyle
};
}
const BAR_MAP = {
vertical: {
offset: "offsetHeight",
scroll: "scrollTop",
scrollSize: "scrollHeight",
size: "height",
key: "vertical",
axis: "Y",
client: "clientY",
direction: "top"
},
horizontal: {
offset: "offsetWidth",
scroll: "scrollLeft",
scrollSize: "scrollWidth",
size: "width",
key: "horizontal",
axis: "X",
client: "clientX",
direction: "left"
}
};
const renderThumbStyle = ({ move, size, bar }) => ({
[bar.size]: size,
transform: `translate${bar.axis}(${move}%)`
});
const thumbProps = buildProps({
vertical: Boolean,
size: String,
move: Number,
ratio: {
type: Number,
required: true
},
always: Boolean
});
const scrollbarContextKey = Symbol("scrollbarContextKey");
function isGreaterThan(a, b, epsilon = 0.03) {
return a - b > epsilon;
}
const barProps = buildProps({
always: {
type: Boolean,
default: true
},
minSize: {
type: Number,
required: true
}
});
const COMPONENT_NAME$2 = "Thumb";
var thumb_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "thumb",
props: thumbProps,
setup(__props) {
const props = __props;
const scrollbar = inject(scrollbarContextKey);
const ns = useNamespace("scrollbar");
if (!scrollbar) throwError(COMPONENT_NAME$2, "can not inject scrollbar context");
const instance = ref();
const thumb = ref();
const thumbState = ref({});
const visible = ref(false);
let cursorDown = false;
let cursorLeave = false;
let baseScrollHeight = 0;
let baseScrollWidth = 0;
let originalOnSelectStart = isClient ? document.onselectstart : null;
const bar = computed(() => BAR_MAP[props.vertical ? "vertical" : "horizontal"]);
const thumbStyle = computed(() => renderThumbStyle({
size: props.size,
move: props.move,
bar: bar.value
}));
const offsetRatio = computed(() => instance.value[bar.value.offset] ** 2 / scrollbar.wrapElement[bar.value.scrollSize] / props.ratio / thumb.value[bar.value.offset]);
const clickThumbHandler = (e) => {
var _a;
e.stopPropagation();
if (e.ctrlKey || [1, 2].includes(e.button)) return;
(_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
startDrag(e);
const el = e.currentTarget;
if (!el) return;
thumbState.value[bar.value.axis] = el[bar.value.offset] - (e[bar.value.client] - el.getBoundingClientRect()[bar.value.direction]);
};
const clickTrackHandler = (e) => {
if (!thumb.value || !instance.value || !scrollbar.wrapElement) return;
const thumbPositionPercentage = (Math.abs(e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) - thumb.value[bar.value.offset] / 2) * 100 * offsetRatio.value / instance.value[bar.value.offset];
scrollbar.wrapElement[bar.value.scroll] = thumbPositionPercentage * scrollbar.wrapElement[bar.value.scrollSize] / 100;
};
const startDrag = (e) => {
e.stopImmediatePropagation();
cursorDown = true;
baseScrollHeight = scrollbar.wrapElement.scrollHeight;
baseScrollWidth = scrollbar.wrapElement.scrollWidth;
document.addEventListener("mousemove", mouseMoveDocumentHandler);
document.addEventListener("mouseup", mouseUpDocumentHandler);
originalOnSelectStart = document.onselectstart;
document.onselectstart = () => false;
};
const mouseMoveDocumentHandler = (e) => {
if (!instance.value || !thumb.value) return;
if (cursorDown === false) return;
const prevPage = thumbState.value[bar.value.axis];
if (!prevPage) return;
const thumbPositionPercentage = ((instance.value.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * -1 - (thumb.value[bar.value.offset] - prevPage)) * 100 * offsetRatio.value / instance.value[bar.value.offset];
if (bar.value.scroll === "scrollLeft") scrollbar.wrapElement[bar.value.scroll] = thumbPositionPercentage * baseScrollWidth / 100;
else scrollbar.wrapElement[bar.value.scroll] = thumbPositionPercentage * baseScrollHeight / 100;
};
const mouseUpDocumentHandler = () => {
cursorDown = false;
thumbState.value[bar.value.axis] = 0;
document.removeEventListener("mousemove", mouseMoveDocumentHandler);
document.removeEventListener("mouseup", mouseUpDocumentHandler);
restoreOnselectstart();
if (cursorLeave) visible.value = false;
};
const mouseMoveScrollbarHandler = () => {
cursorLeave = false;
visible.value = !!props.size;
};
const mouseLeaveScrollbarHandler = () => {
cursorLeave = true;
visible.value = cursorDown;
};
onBeforeUnmount(() => {
restoreOnselectstart();
document.removeEventListener("mouseup", mouseUpDocumentHandler);
});
const restoreOnselectstart = () => {
if (document.onselectstart !== originalOnSelectStart) document.onselectstart = originalOnSelectStart;
};
useEventListener(toRef(scrollbar, "scrollbarElement"), "mousemove", mouseMoveScrollbarHandler);
useEventListener(toRef(scrollbar, "scrollbarElement"), "mouseleave", mouseLeaveScrollbarHandler);
return (_ctx, _cache) => {
return openBlock(), createBlock(Transition, {
name: unref(ns).b("fade"),
persisted: ""
}, {
default: withCtx(() => [withDirectives(createElementVNode("div", {
ref_key: "instance",
ref: instance,
class: normalizeClass([unref(ns).e("bar"), unref(ns).is(bar.value.key)]),
onMousedown: clickTrackHandler,
onClick: _cache[0] || (_cache[0] = withModifiers(() => {
}, ["stop"]))
}, [createElementVNode("div", {
ref_key: "thumb",
ref: thumb,
class: normalizeClass(unref(ns).e("thumb")),
style: normalizeStyle(thumbStyle.value),
onMousedown: clickThumbHandler
}, null, 38)], 34), [[vShow, __props.always || visible.value]])]),
_: 1
}, 8, ["name"]);
};
}
});
var thumb_default = thumb_vue_vue_type_script_setup_true_lang_default;
var bar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "bar",
props: barProps,
setup(__props, { expose: __expose }) {
const props = __props;
const scrollbar = inject(scrollbarContextKey);
const moveX = ref(0);
const moveY = ref(0);
const sizeWidth = ref("");
const sizeHeight = ref("");
const ratioY = ref(1);
const ratioX = ref(1);
const handleScroll = (wrap) => {
if (wrap) {
const offsetHeight = wrap.offsetHeight - 4;
const offsetWidth = wrap.offsetWidth - 4;
moveY.value = wrap.scrollTop * 100 / offsetHeight * ratioY.value;
moveX.value = wrap.scrollLeft * 100 / offsetWidth * ratioX.value;
}
};
const update = () => {
const wrap = scrollbar == null ? void 0 : scrollbar.wrapElement;
if (!wrap) return;
const offsetHeight = wrap.offsetHeight - 4;
const offsetWidth = wrap.offsetWidth - 4;
const originalHeight = offsetHeight ** 2 / wrap.scrollHeight;
const originalWidth = offsetWidth ** 2 / wrap.scrollWidth;
const height = Math.max(originalHeight, props.minSize);
const width = Math.max(originalWidth, props.minSize);
ratioY.value = originalHeight / (offsetHeight - originalHeight) / (height / (offsetHeight - height));
ratioX.value = originalWidth / (offsetWidth - originalWidth) / (width / (offsetWidth - width));
sizeHeight.value = height + 4 < offsetHeight ? `${height}px` : "";
sizeWidth.value = width + 4 < offsetWidth ? `${width}px` : "";
};
__expose({
handleScroll,
update
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock(Fragment, null, [createVNode(thumb_default, {
move: moveX.value,
ratio: ratioX.value,
size: sizeWidth.value,
always: __props.always
}, null, 8, [
"move",
"ratio",
"size",
"always"
]), createVNode(thumb_default, {
move: moveY.value,
ratio: ratioY.value,
size: sizeHeight.value,
vertical: "",
always: __props.always
}, null, 8, [
"move",
"ratio",
"size",
"always"
])], 64);
};
}
});
var bar_default = bar_vue_vue_type_script_setup_true_lang_default;
const _hoisted_1$2 = ["tabindex"];
const COMPONENT_NAME$1 = "ElScrollbar";
var scrollbar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
name: COMPONENT_NAME$1,
__name: "scrollbar",
props: scrollbarProps,
emits: scrollbarEmits,
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emit = __emit;
const ns = useNamespace("scrollbar");
let stopResizeObserver = void 0;
let stopWrapResizeObserver = void 0;
let stopResizeListener = void 0;
let wrapScrollTop = 0;
let wrapScrollLeft = 0;
let direction = "";
const distanceScrollState = {
bottom: false,
top: false,
right: false,
left: false
};
const scrollbarRef = ref();
const wrapRef = ref();
const resizeRef = ref();
const barRef = ref();
const wrapStyle = computed(() => {
const style = {};
const height = addUnit(props.height);
const maxHeight = addUnit(props.maxHeight);
if (height) style.height = height;
if (maxHeight) style.maxHeight = maxHeight;
return [props.wrapStyle, style];
});
const wrapKls = computed(() => {
return [
props.wrapClass,
ns.e("wrap"),
{ [ns.em("wrap", "hidden-default")]: !props.native }
];
});
const resizeKls = computed(() => {
return [ns.e("view"), props.viewClass];
});
const shouldSkipDirection = (direction2) => {
return distanceScrollState[direction2] ?? false;
};
const DIRECTION_PAIRS = {
top: "bottom",
bottom: "top",
left: "right",
right: "left"
};
const updateTriggerStatus = (arrivedStates) => {
const oppositeDirection = DIRECTION_PAIRS[direction];
if (!oppositeDirection) return;
const arrived = arrivedStates[direction];
const oppositeArrived = arrivedStates[oppositeDirection];
if (arrived && !distanceScrollState[direction]) distanceScrollState[direction] = true;
if (!oppositeArrived && distanceScrollState[oppositeDirection]) distanceScrollState[oppositeDirection] = false;
};
const handleScroll = () => {
var _a;
if (wrapRef.value) {
(_a = barRef.value) == null ? void 0 : _a.handleScroll(wrapRef.value);
const prevTop = wrapScrollTop;
const prevLeft = wrapScrollLeft;
wrapScrollTop = wrapRef.value.scrollTop;
wrapScrollLeft = wrapRef.value.scrollLeft;
const arrivedStates = {
bottom: !isGreaterThan(wrapRef.value.scrollHeight - props.distance, wrapRef.value.clientHeight + wrapScrollTop),
top: wrapScrollTop <= props.distance && prevTop !== 0,
right: !isGreaterThan(wrapRef.value.scrollWidth - props.distance, wrapRef.value.clientWidth + wrapScrollLeft) && prevLeft !== wrapScrollLeft,
left: wrapScrollLeft <= props.distance && prevLeft !== 0
};
emit("scroll", {
scrollTop: wrapScrollTop,
scrollLeft: wrapScrollLeft
});
if (prevTop !== wrapScrollTop) direction = wrapScrollTop > prevTop ? "bottom" : "top";
if (prevLeft !== wrapScrollLeft) direction = wrapScrollLeft > prevLeft ? "right" : "left";
if (props.distance > 0) {
if (shouldSkipDirection(direction)) return;
updateTriggerStatus(arrivedStates);
}
if (arrivedStates[direction]) emit("end-reached", direction);
}
};
function scrollTo(arg1, arg2) {
if (isObject(arg1)) wrapRef.value.scrollTo(arg1);
else if (isNumber(arg1) && isNumber(arg2)) wrapRef.value.scrollTo(arg1, arg2);
}
const setScrollTop = (value) => {
if (!isNumber(value)) {
debugWarn(COMPONENT_NAME$1, "value must be a number");
return;
}
wrapRef.value.scrollTop = value;
};
const setScrollLeft = (value) => {
if (!isNumber(value)) {
debugWarn(COMPONENT_NAME$1, "value must be a number");
return;
}
wrapRef.value.scrollLeft = value;
};
const update = () => {
var _a, _b;
(_a = barRef.value) == null ? void 0 : _a.update();
distanceScrollState[direction] = false;
if (wrapRef.value) (_b = barRef.value) == null ? void 0 : _b.handleScroll(wrapRef.value);
};
watch(() => props.noresize, (noresize) => {
if (noresize) {
stopResizeObserver == null ? void 0 : stopResizeObserver();
stopWrapResizeObserver == null ? void 0 : stopWrapResizeObserver();
stopResizeListener == null ? void 0 : stopResizeListener();
} else {
({ stop: stopResizeObserver } = useResizeObserver(resizeRef, update));
({ stop: stopWrapResizeObserver } = useResizeObserver(wrapRef, update));
stopResizeListener = useEventListener("resize", update);
}
}, { immediate: true });
watch(() => [props.maxHeight, props.height], () => {
if (!props.native) nextTick(() => {
update();
});
});
provide(scrollbarContextKey, reactive({
scrollbarElement: scrollbarRef,
wrapElement: wrapRef
}));
onActivated(() => {
if (wrapRef.value) {
wrapRef.value.scrollTop = wrapScrollTop;
wrapRef.value.scrollLeft = wrapScrollLeft;
}
});
onMounted(() => {
if (!props.native) nextTick(() => {
update();
});
});
onUpdated(() => update());
__expose({
/** @description scrollbar wrap ref */
wrapRef,
/** @description update scrollbar state manually */
update,
/** @description scrolls to a particular set of coordinates */
scrollTo,
/** @description set distance to scroll top */
setScrollTop,
/** @description set distance to scroll left */
setScrollLeft,
/** @description handle scroll event */
handleScroll
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref_key: "scrollbarRef",
ref: scrollbarRef,
class: normalizeClass(unref(ns).b())
}, [createElementVNode("div", {
ref_key: "wrapRef",
ref: wrapRef,
class: normalizeClass(wrapKls.value),
style: normalizeStyle(wrapStyle.value),
tabindex: __props.tabindex,
onScroll: handleScroll
}, [(openBlock(), createBlock(resolveDynamicComponent(__props.tag), {
id: __props.id,
ref_key: "resizeRef",
ref: resizeRef,
class: normalizeClass(resizeKls.value),
style: normalizeStyle(__props.viewStyle),
role: __props.role,
"aria-label": __props.ariaLabel,
"aria-orientation": __props.ariaOrientation
}, {
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
_: 3
}, 8, [
"id",
"class",
"style",
"role",
"aria-label",
"aria-orientation"
]))], 46, _hoisted_1$2), !__props.native ? (openBlock(), createBlock(bar_default, {
key: 0,
ref_key: "barRef",
ref: barRef,
always: __props.always,
"min-size": __props.minSize
}, null, 8, ["always", "min-size"])) : createCommentVNode("v-if", true)], 2);
};
}
});
var scrollbar_default = scrollbar_vue_vue_type_script_setup_true_lang_default;
const ElScrollbar = withInstall(scrollbar_default);
const nodeList = /* @__PURE__ */ new Map();
if (isClient) {
let startClick;
document.addEventListener("mousedown", (e) => startClick = e);
document.addEventListener("mouseup", (e) => {
if (startClick) {
for (const handlers of nodeList.values()) for (const { documentHandler } of handlers) documentHandler(e, startClick);
startClick = void 0;
}
});
}
function createDocumentHandler(el, binding) {
let excludes = [];
if (isArray(binding.arg)) excludes = binding.arg;
else if (isElement(binding.arg)) excludes.push(binding.arg);
return function(mouseup, mousedown) {
const popperRef = binding.instance.popperRef;
const mouseUpTarget = mouseup.target;
const mouseDownTarget = mousedown == null ? void 0 : mousedown.target;
const isBound = !binding || !binding.instance;
const isTargetExists = !mouseUpTarget || !mouseDownTarget;
const isContainedByEl = el.contains(mouseUpTarget) || el.contains(mouseDownTarget);
const isSelf = el === mouseUpTarget;
const isTargetExcluded = excludes.length && excludes.some((item) => item == null ? void 0 : item.contains(mouseUpTarget)) || excludes.length && excludes.includes(mouseDownTarget);
const isContainedByPopper = popperRef && (popperRef.contains(mouseUpTarget) || popperRef.contains(mouseDownTarget));
if (isBound || isTargetExists || isContainedByEl || isSelf || isTargetExcluded || isContainedByPopper) return;
binding.value(mouseup, mousedown);
};
}
const ClickOutside = {
beforeMount(el, binding) {
if (!nodeList.has(el)) nodeList.set(el, []);
nodeList.get(el).push({
documentHandler: createDocumentHandler(el, binding),
bindingFn: binding.value
});
},
updated(el, binding) {
if (!nodeList.has(el)) nodeList.set(el, []);
const handlers = nodeList.get(el);
const oldHandlerIndex = handlers.findIndex((item) => item.bindingFn === binding.oldValue);
const newHandler = {
documentHandler: createDocumentHandler(el, binding),
bindingFn: binding.value
};
if (oldHandlerIndex >= 0) handlers.splice(oldHandlerIndex, 1, newHandler);
else handlers.push(newHandler);
},
unmounted(el) {
nodeList.delete(el);
}
};
const _hoisted_1$1 = ["aria-label"];
const _hoisted_2$1 = ["aria-label"];
var tag_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
name: "ElTag",
__name: "tag",
props: tagProps,
emits: tagEmits,
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const tagSize = useFormSize();
const { t } = useLocale();
const ns = useNamespace("tag");
const containerKls = computed(() => {
const { type, hit, effect, closable, round } = props;
return [
ns.b(),
ns.is("closable", closable),
ns.m(type || "primary"),
ns.m(tagSize.value),
ns.m(effect),
ns.is("hit", hit),
ns.is("round", round)
];
});
const handleClose = (event) => {
emit("close", event);
};
const handleClick = (event) => {
emit("click", event);
};
const handleVNodeMounted = (vnode) => {
var _a, _b, _c;
if ((_c = (_b = (_a = vnode == null ? void 0 : vnode.component) == null ? void 0 : _a.subTree) == null ? void 0 : _b.component) == null ? void 0 : _c.bum) vnode.component.subTree.component.bum = null;
};
return (_ctx, _cache) => {
return __props.disableTransitions ? (openBlock(), createElementBlock("span", {
key: 0,
class: normalizeClass(containerKls.value),
style: normalizeStyle({ backgroundColor: __props.color }),
onClick: handleClick
}, [createElementVNode("span", { class: normalizeClass(unref(ns).e("content")) }, [renderSlot(_ctx.$slots, "default")], 2), __props.closable ? (openBlock(), createElementBlock("button", {
key: 0,
"aria-label": unref(t)("el.tag.close"),
class: normalizeClass(unref(ns).e("close")),
type: "button",
onClick: withModifiers(handleClose, ["stop"])
}, [createVNode(unref(ElIcon), null, {
default: withCtx(() => [createVNode(unref(close_default))]),
_: 1
})], 10, _hoisted_1$1)) : createCommentVNode("v-if", true)], 6)) : (openBlock(), createBlock(Transition, {
key: 1,
name: `${unref(ns).namespace.value}-zoom-in-center`,
appear: "",
onVnodeMounted: handleVNodeMounted
}, {
default: withCtx(() => [createElementVNode("span", {
class: normalizeClass(containerKls.value),
style: normalizeStyle({ backgroundColor: __props.color }),
onClick: handleClick
}, [createElementVNode("span", { class: normalizeClass(unref(ns).e("content")) }, [renderSlot(_ctx.$slots, "default")], 2), __props.closable ? (openBlock(), createElementBlock("button", {
key: 0,
"aria-label": unref(t)("el.tag.close"),
class: normalizeClass(unref(ns).e("close")),
type: "button",
onClick: withModifiers(handleClose, ["stop"])
}, [createVNode(unref(ElIcon), null, {
default: withCtx(() => [createVNode(unref(close_default))]),
_: 1
})], 10, _hoisted_2$1)) : createCommentVNode("v-if", true)], 6)]),
_: 3
}, 8, ["name"]));
};
}
});
var tag_default = tag_vue_vue_type_script_setup_true_lang_default;
const ElTag = withInstall(tag_default);
var select_dropdown_vue_vue_type_script_lang_default = defineComponent({
name: "ElSelectDropdown",
componentName: "ElSelectDropdown",
setup() {
const select = inject(selectKey);
const ns = useNamespace("select");
const popperClass = computed(() => select.props.popperClass);
const isMultiple = computed(() => select.props.multiple);
const isFitInputWidth = computed(() => select.props.fitInputWidth);
const minWidth = ref("");
function updateMinWidth() {
var _a;
const offsetWidth = (_a = select.selectRef) == null ? void 0 : _a.offsetWidth;
if (offsetWidth) minWidth.value = `${offsetWidth - 2}px`;
else minWidth.value = "";
}
onMounted(() => {
updateMinWidth();
useResizeObserver(select.selectRef, updateMinWidth);
});
return {
ns,
minWidth,
popperClass,
isMultiple,
isFitInputWidth
};
}
});
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createElementBlock("div", {
class: normalizeClass([
_ctx.ns.b("dropdown"),
_ctx.ns.is("multiple", _ctx.isMultiple),
_ctx.popperClass
]),
style: normalizeStyle({ [_ctx.isFitInputWidth ? "width" : "minWidth"]: _ctx.minWidth })
}, [
_ctx.$slots.header ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(_ctx.ns.be("dropdown", "header"))
}, [renderSlot(_ctx.$slots, "header")], 2)) : createCommentVNode("v-if", true),
renderSlot(_ctx.$slots, "default"),
_ctx.$slots.footer ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(_ctx.ns.be("dropdown", "footer"))
}, [renderSlot(_ctx.$slots, "footer")], 2)) : createCommentVNode("v-if", true)
], 6);
}
var select_dropdown_default = /* @__PURE__ */ _plugin_vue_export_helper_default(select_dropdown_vue_vue_type_script_lang_default, [["render", _sfc_render$1]]);
const useSelect = (props, emit) => {
const { t } = useLocale();
const slots = useSlots();
const contentId = useId();
const nsSelect = useNamespace("select");
const nsInput = useNamespace("input");
const states = reactive({
inputValue: "",
options: /* @__PURE__ */ new Map(),
cachedOptions: /* @__PURE__ */ new Map(),
optionValues: [],
selected: [],
selectionWidth: 0,
collapseItemWidth: 0,
selectedLabel: "",
hoveringIndex: -1,
previousQuery: null,
inputHovering: false,
menuVisibleOnFocus: false,
isBeforeHide: false
});
const selectRef = ref();
const selectionRef = ref();
const tooltipRef = ref();
const tagTooltipRef = ref();
const inputRef = ref();
const prefixRef = ref();
const suffixRef = ref();
const menuRef = ref();
const tagMenuRef = ref();
const collapseItemRef = ref();
const scrollbarRef = ref();
const expanded = ref(false);
const hoverOption = ref();
const debouncing = ref(false);
const { form, formItem } = useFormItem();
const { inputId } = useFormItemInputId(props, { formItemContext: formItem });
const { valueOnClear, isEmptyValue } = useEmptyValues(props);
const { isComposing, handleCompositionStart, handleCompositionUpdate, handleCompositionEnd } = useComposition({ afterComposition: (e) => onInput(e) });
const selectDisabled = useFormDisabled();
const { wrapperRef, isFocused, handleBlur } = useFocusController(inputRef, {
disabled: selectDisabled,
afterFocus() {
if (props.automaticDropdown && !expanded.value) {
expanded.value = true;
states.menuVisibleOnFocus = true;
}
},
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;
expanded.value = false;
states.menuVisibleOnFocus = false;
if (props.validateEvent) (_a = formItem == null ? void 0 : formItem.validate) == null ? void 0 : _a.call(formItem, "blur").catch(NOOP);
}
});
const hasModelValue = computed(() => {
return isArray(props.modelValue) ? props.modelValue.length > 0 : !isEmptyValue(props.modelValue);
});
const needStatusIcon = computed(() => (form == null ? void 0 : form.statusIcon) ?? false);
const showClearBtn = computed(() => {
return props.clearable && !selectDisabled.value && hasModelValue.value && (isFocused.value || states.inputHovering);
});
const iconComponent = computed(() => props.remote && props.filterable && !props.remoteShowSuffix ? "" : props.suffixIcon);
const iconReverse = computed(() => nsSelect.is("reverse", !!(iconComponent.value && expanded.value)));
const validateState = computed(() => (formItem == null ? void 0 : formItem.validateState) || "");
const validateIcon = computed(() => validateState.value && ValidateComponentsMap[validateState.value]);
const debounce = computed(() => props.remote ? props.debounce : 0);
const isRemoteSearchEmpty = computed(() => props.remote && !states.inputValue && states.options.size === 0);
const emptyText = computed(() => {
if (props.loading) return props.loadingText || t("el.select.loading");
else {
if (props.filterable && states.inputValue && states.options.size > 0 && filteredOptionsCount.value === 0) return props.noMatchText || t("el.select.noMatch");
if (states.options.size === 0) return props.noDataText || t("el.select.noData");
}
return null;
});
const filteredOptionsCount = computed(() => optionsArray.value.filter((option) => option.visible).length);
const optionsArray = computed(() => {
const list = Array.from(states.options.values());
const newList = [];
states.optionValues.forEach((item) => {
const index = list.findIndex((i) => i.value === item);
if (index > -1) newList.push(list[index]);
});
return newList.length >= list.length ? newList : list;
});
const cachedOptionsArray = computed(() => Array.from(states.cachedOptions.values()));
const showNewOption = computed(() => {
const hasExistingOption = optionsArray.value.filter((option) => {
return !option.created;
}).some((option) => {
return option.currentLabel === states.inputValue;
});
return props.filterable && props.allowCreate && states.inputValue !== "" && !hasExistingOption;
});
const updateOptions = () => {
if (props.filterable && isFunction