This commit is contained in:
2025-09-19 14:25:20 +08:00
parent 269893a435
commit fbf3f77229
24949 changed files with 2839404 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
import Mention from './src/mention.vue';
import type { SFCWithInstall } from 'element-plus/es/utils';
export declare const ElMention: SFCWithInstall<typeof Mention>;
export default ElMention;
export * from './src/mention';

View File

@@ -0,0 +1,8 @@
import Mention from './src/mention2.mjs';
export { mentionDefaultProps, mentionEmits, mentionProps } from './src/mention.mjs';
import { withInstall } from '../../utils/vue/install.mjs';
const ElMention = withInstall(Mention);
export { ElMention, ElMention as default };
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":["../../../../../packages/components/mention/index.ts"],"sourcesContent":["import { withInstall } from '@element-plus/utils'\nimport Mention from './src/mention.vue'\n\nimport type { SFCWithInstall } from '@element-plus/utils'\n\nexport const ElMention: SFCWithInstall<typeof Mention> = withInstall(Mention)\nexport default ElMention\n\nexport * from './src/mention'\n"],"names":[],"mappings":";;;;AAEY,MAAC,SAAS,GAAG,WAAW,CAAC,OAAO;;;;"}

View File

@@ -0,0 +1,32 @@
import type { MentionCtx, MentionOption } from './types';
export declare const filterOption: (pattern: string, option: MentionOption) => boolean;
export declare const getMentionCtx: (inputEl: HTMLInputElement | HTMLTextAreaElement, prefix: string | string[], split: string) => MentionCtx | undefined;
/**
* fork from textarea-caret-position
* https://github.com/component/textarea-caret-position
* The MIT License (MIT)
* Copyright (c) 2015 Jonathan Ong me@jongleberry.com
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
export declare const getCursorPosition: (element: HTMLInputElement | HTMLTextAreaElement, options?: {
debug: boolean;
useSelectionEnd: boolean;
}) => {
top: number;
left: number;
height: number;
};

View File

@@ -0,0 +1,151 @@
import { castArray } from 'lodash-unified';
import { isFirefox } from '../../../utils/browser.mjs';
const filterOption = (pattern, option) => {
const lowerCase = pattern.toLowerCase();
const label = option.label || option.value || "";
return label.toLowerCase().includes(lowerCase);
};
const getMentionCtx = (inputEl, prefix, split) => {
const { selectionEnd } = inputEl;
if (selectionEnd === null)
return;
const inputValue = inputEl.value;
const prefixArray = castArray(prefix);
let splitIndex = -1;
let mentionCtx;
for (let i = selectionEnd - 1; i >= 0; --i) {
const char = inputValue[i];
if (char === split || char === "\n" || char === "\r") {
splitIndex = i;
continue;
}
if (prefixArray.includes(char)) {
const end = splitIndex === -1 ? selectionEnd : splitIndex;
const pattern = inputValue.slice(i + 1, end);
mentionCtx = {
pattern,
start: i + 1,
end,
prefix: char,
prefixIndex: i,
splitIndex,
selectionEnd
};
break;
}
}
return mentionCtx;
};
const getCursorPosition = (element, options = {
debug: false,
useSelectionEnd: false
}) => {
const selectionStart = element.selectionStart !== null ? element.selectionStart : 0;
const selectionEnd = element.selectionEnd !== null ? element.selectionEnd : 0;
const position = options.useSelectionEnd ? selectionEnd : selectionStart;
const properties = [
"direction",
"boxSizing",
"width",
"height",
"overflowX",
"overflowY",
"borderTopWidth",
"borderRightWidth",
"borderBottomWidth",
"borderLeftWidth",
"borderStyle",
"paddingTop",
"paddingRight",
"paddingBottom",
"paddingLeft",
"fontStyle",
"fontVariant",
"fontWeight",
"fontStretch",
"fontSize",
"fontSizeAdjust",
"lineHeight",
"fontFamily",
"textAlign",
"textTransform",
"textIndent",
"textDecoration",
"letterSpacing",
"wordSpacing",
"tabSize",
"MozTabSize"
];
if (options.debug) {
const el = document.querySelector("#input-textarea-caret-position-mirror-div");
if (el == null ? void 0 : el.parentNode)
el.parentNode.removeChild(el);
}
const div = document.createElement("div");
div.id = "input-textarea-caret-position-mirror-div";
document.body.appendChild(div);
const style = div.style;
const computed = window.getComputedStyle(element);
const isInput = element.nodeName === "INPUT";
style.whiteSpace = isInput ? "nowrap" : "pre-wrap";
if (!isInput)
style.wordWrap = "break-word";
style.position = "absolute";
if (!options.debug)
style.visibility = "hidden";
properties.forEach((prop) => {
if (isInput && prop === "lineHeight") {
if (computed.boxSizing === "border-box") {
const height = Number.parseInt(computed.height);
const outerHeight = Number.parseInt(computed.paddingTop) + Number.parseInt(computed.paddingBottom) + Number.parseInt(computed.borderTopWidth) + Number.parseInt(computed.borderBottomWidth);
const targetHeight = outerHeight + Number.parseInt(computed.lineHeight);
if (height > targetHeight) {
style.lineHeight = `${height - outerHeight}px`;
} else if (height === targetHeight) {
style.lineHeight = computed.lineHeight;
} else {
style.lineHeight = "0";
}
} else {
style.lineHeight = computed.height;
}
} else {
style[prop] = computed[prop];
}
});
if (isFirefox()) {
if (element.scrollHeight > Number.parseInt(computed.height)) {
style.overflowY = "scroll";
}
} else {
style.overflow = "hidden";
}
div.textContent = element.value.slice(0, Math.max(0, position));
if (isInput && div.textContent) {
div.textContent = div.textContent.replace(/\s/g, "\xA0");
}
const span = document.createElement("span");
span.textContent = element.value.slice(Math.max(0, position)) || ".";
span.style.position = "relative";
span.style.left = `${-element.scrollLeft}px`;
span.style.top = `${-element.scrollTop}px`;
div.appendChild(span);
const relativePosition = {
top: span.offsetTop + Number.parseInt(computed.borderTopWidth),
left: span.offsetLeft + Number.parseInt(computed.borderLeftWidth),
height: Number.parseInt(computed.fontSize) * 1.5
};
if (options.debug) {
span.style.backgroundColor = "#aaa";
} else {
document.body.removeChild(div);
}
if (relativePosition.left >= element.clientWidth) {
relativePosition.left = element.clientWidth;
}
return relativePosition;
};
export { filterOption, getCursorPosition, getMentionCtx };
//# sourceMappingURL=helper.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
import type { MentionOption } from './types';
export declare const mentionDropdownProps: {
options: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => MentionOption[]) | (() => MentionOption[]) | ((new (...args: any[]) => MentionOption[]) | (() => MentionOption[]))[], unknown, unknown, () => never[], boolean>;
loading: BooleanConstructor;
disabled: BooleanConstructor;
contentId: StringConstructor;
ariaLabel: StringConstructor;
};
export declare const mentionDropdownEmits: {
select: (option: MentionOption) => boolean;
};

View File

@@ -0,0 +1,19 @@
import { buildProps, definePropType } from '../../../utils/vue/props/runtime.mjs';
import { isString } from '@vue/shared';
const mentionDropdownProps = buildProps({
options: {
type: definePropType(Array),
default: () => []
},
loading: Boolean,
disabled: Boolean,
contentId: String,
ariaLabel: String
});
const mentionDropdownEmits = {
select: (option) => isString(option.value)
};
export { mentionDropdownEmits, mentionDropdownProps };
//# sourceMappingURL=mention-dropdown.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"mention-dropdown.mjs","sources":["../../../../../../packages/components/mention/src/mention-dropdown.ts"],"sourcesContent":["import { buildProps, definePropType, isString } from '@element-plus/utils'\n\nimport type { MentionOption } from './types'\n\nexport const mentionDropdownProps = buildProps({\n options: {\n type: definePropType<MentionOption[]>(Array),\n default: () => [],\n },\n loading: Boolean,\n disabled: Boolean,\n contentId: String,\n ariaLabel: String,\n})\n\nexport const mentionDropdownEmits = {\n select: (option: MentionOption) => isString(option.value),\n}\n"],"names":[],"mappings":";;;AACY,MAAC,oBAAoB,GAAG,UAAU,CAAC;AAC/C,EAAE,OAAO,EAAE;AACX,IAAI,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC;AAC/B,IAAI,OAAO,EAAE,MAAM,EAAE;AACrB,GAAG;AACH,EAAE,OAAO,EAAE,OAAO;AAClB,EAAE,QAAQ,EAAE,OAAO;AACnB,EAAE,SAAS,EAAE,MAAM;AACnB,EAAE,SAAS,EAAE,MAAM;AACnB,CAAC,EAAE;AACS,MAAC,oBAAoB,GAAG;AACpC,EAAE,MAAM,EAAE,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;AAC5C;;;;"}

View File

@@ -0,0 +1,43 @@
import type { MentionOption } from './types';
declare function __VLS_template(): {
header?(_: {}): any;
label?(_: {
item: MentionOption;
index: number;
}): any;
loading?(_: {}): any;
footer?(_: {}): any;
};
declare const __VLS_component: import("vue").DefineComponent<{
options: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => MentionOption[]) | (() => MentionOption[]) | ((new (...args: any[]) => MentionOption[]) | (() => MentionOption[]))[], unknown, unknown, () => never[], boolean>;
loading: BooleanConstructor;
disabled: BooleanConstructor;
contentId: StringConstructor;
ariaLabel: StringConstructor;
}, {
hoveringIndex: import("vue").Ref<number>;
navigateOptions: (direction: "next" | "prev") => void;
selectHoverOption: () => void;
hoverOption: import("vue").ComputedRef<MentionOption>;
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
select: (option: MentionOption) => void;
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
options: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => MentionOption[]) | (() => MentionOption[]) | ((new (...args: any[]) => MentionOption[]) | (() => MentionOption[]))[], unknown, unknown, () => never[], boolean>;
loading: BooleanConstructor;
disabled: BooleanConstructor;
contentId: StringConstructor;
ariaLabel: StringConstructor;
}>> & {
onSelect?: ((option: MentionOption) => any) | undefined;
}, {
disabled: boolean;
loading: boolean;
options: MentionOption[];
}>;
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
export default _default;
type __VLS_WithTemplateSlots<T, S> = T & {
new (): {
$slots: S;
};
};

View File

@@ -0,0 +1,170 @@
import { defineComponent, ref, computed, watch, openBlock, createElementBlock, normalizeClass, unref, renderSlot, createCommentVNode, withDirectives, createVNode, withCtx, Fragment, renderList, withModifiers, createElementVNode, toDisplayString, vShow, createTextVNode, nextTick } from 'vue';
import { ElScrollbar } from '../../scrollbar/index.mjs';
import { mentionDropdownProps, mentionDropdownEmits } from './mention-dropdown.mjs';
import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
import { useLocale } from '../../../hooks/use-locale/index.mjs';
import { scrollIntoView } from '../../../utils/dom/scroll.mjs';
const __default__ = defineComponent({
name: "ElMentionDropdown"
});
const _sfc_main = /* @__PURE__ */ defineComponent({
...__default__,
props: mentionDropdownProps,
emits: mentionDropdownEmits,
setup(__props, { expose, emit }) {
const props = __props;
const ns = useNamespace("mention");
const { t } = useLocale();
const hoveringIndex = ref(-1);
const scrollbarRef = ref();
const optionRefs = ref();
const dropdownRef = ref();
const optionkls = (item, index) => [
ns.be("dropdown", "item"),
ns.is("hovering", hoveringIndex.value === index),
ns.is("disabled", item.disabled || props.disabled)
];
const handleSelect = (item) => {
if (item.disabled || props.disabled)
return;
emit("select", item);
};
const handleMouseEnter = (index) => {
hoveringIndex.value = index;
};
const filteredAllDisabled = computed(() => props.disabled || props.options.every((item) => item.disabled));
const hoverOption = computed(() => props.options[hoveringIndex.value]);
const selectHoverOption = () => {
if (!hoverOption.value)
return;
emit("select", hoverOption.value);
};
const navigateOptions = (direction) => {
const { options } = props;
if (options.length === 0 || filteredAllDisabled.value)
return;
if (direction === "next") {
hoveringIndex.value++;
if (hoveringIndex.value === options.length) {
hoveringIndex.value = 0;
}
} else if (direction === "prev") {
hoveringIndex.value--;
if (hoveringIndex.value < 0) {
hoveringIndex.value = options.length - 1;
}
}
const option = options[hoveringIndex.value];
if (option.disabled) {
navigateOptions(direction);
return;
}
nextTick(() => scrollToOption(option));
};
const scrollToOption = (option) => {
var _a, _b, _c, _d;
const { options } = props;
const index = options.findIndex((item) => item.value === option.value);
const target = (_a = optionRefs.value) == null ? void 0 : _a[index];
if (target) {
const menu = (_c = (_b = dropdownRef.value) == null ? void 0 : _b.querySelector) == null ? void 0 : _c.call(_b, `.${ns.be("dropdown", "wrap")}`);
if (menu) {
scrollIntoView(menu, target);
}
}
(_d = scrollbarRef.value) == null ? void 0 : _d.handleScroll();
};
const resetHoveringIndex = () => {
if (filteredAllDisabled.value || props.options.length === 0) {
hoveringIndex.value = -1;
} else {
hoveringIndex.value = 0;
}
};
watch(() => props.options, resetHoveringIndex, {
immediate: true
});
expose({
hoveringIndex,
navigateOptions,
selectHoverOption,
hoverOption
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref_key: "dropdownRef",
ref: dropdownRef,
class: normalizeClass(unref(ns).b("dropdown"))
}, [
_ctx.$slots.header ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(unref(ns).be("dropdown", "header"))
}, [
renderSlot(_ctx.$slots, "header")
], 2)) : createCommentVNode("v-if", true),
withDirectives(createVNode(unref(ElScrollbar), {
id: _ctx.contentId,
ref_key: "scrollbarRef",
ref: scrollbarRef,
tag: "ul",
"wrap-class": unref(ns).be("dropdown", "wrap"),
"view-class": unref(ns).be("dropdown", "list"),
role: "listbox",
"aria-label": _ctx.ariaLabel,
"aria-orientation": "vertical"
}, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.options, (item, index) => {
return openBlock(), createElementBlock("li", {
id: `${_ctx.contentId}-${index}`,
ref_for: true,
ref_key: "optionRefs",
ref: optionRefs,
key: index,
class: normalizeClass(optionkls(item, index)),
role: "option",
"aria-disabled": item.disabled || _ctx.disabled || void 0,
"aria-selected": hoveringIndex.value === index,
onMousemove: ($event) => handleMouseEnter(index),
onClick: withModifiers(($event) => handleSelect(item), ["stop"])
}, [
renderSlot(_ctx.$slots, "label", {
item,
index
}, () => {
var _a;
return [
createElementVNode("span", null, toDisplayString((_a = item.label) != null ? _a : item.value), 1)
];
})
], 42, ["id", "aria-disabled", "aria-selected", "onMousemove", "onClick"]);
}), 128))
]),
_: 3
}, 8, ["id", "wrap-class", "view-class", "aria-label"]), [
[vShow, _ctx.options.length > 0 && !_ctx.loading]
]),
_ctx.loading ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(unref(ns).be("dropdown", "loading"))
}, [
renderSlot(_ctx.$slots, "loading", {}, () => [
createTextVNode(toDisplayString(unref(t)("el.mention.loading")), 1)
])
], 2)) : createCommentVNode("v-if", true),
_ctx.$slots.footer ? (openBlock(), createElementBlock("div", {
key: 2,
class: normalizeClass(unref(ns).be("dropdown", "footer"))
}, [
renderSlot(_ctx.$slots, "footer")
], 2)) : createCommentVNode("v-if", true)
], 2);
};
}
});
var ElMentionDropdown = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "mention-dropdown.vue"]]);
export { ElMentionDropdown as default };
//# sourceMappingURL=mention-dropdown2.mjs.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,80 @@
import { filterOption } from './helper.mjs';
import { buildProps, definePropType } from '../../../utils/vue/props/runtime.mjs';
import { inputProps } from '../../input/src/input.mjs';
import { isString, isFunction, isObject } from '@vue/shared';
import { UPDATE_MODEL_EVENT } from '../../../constants/event.mjs';
const mentionProps = buildProps({
...inputProps,
options: {
type: definePropType(Array),
default: () => []
},
prefix: {
type: definePropType([String, Array]),
default: "@",
validator: (val) => {
if (isString(val))
return val.length === 1;
return val.every((v) => isString(v) && v.length === 1);
}
},
split: {
type: String,
default: " ",
validator: (val) => val.length === 1
},
filterOption: {
type: definePropType([Boolean, Function]),
default: () => filterOption,
validator: (val) => {
if (val === false)
return true;
return isFunction(val);
}
},
placement: {
type: definePropType(String),
default: "bottom"
},
showArrow: Boolean,
offset: {
type: Number,
default: 0
},
whole: Boolean,
checkIsWhole: {
type: definePropType(Function)
},
modelValue: String,
loading: Boolean,
popperClass: {
type: String,
default: ""
},
popperOptions: {
type: definePropType(Object),
default: () => ({})
},
props: {
type: definePropType(Object),
default: () => mentionDefaultProps
}
});
const mentionEmits = {
[UPDATE_MODEL_EVENT]: (value) => isString(value),
"whole-remove": (pattern, prefix) => isString(pattern) && isString(prefix),
input: (value) => isString(value),
search: (pattern, prefix) => isString(pattern) && isString(prefix),
select: (option, prefix) => isObject(option) && isString(prefix),
focus: (evt) => evt instanceof FocusEvent,
blur: (evt) => evt instanceof FocusEvent
};
const mentionDefaultProps = {
value: "value",
label: "label",
disabled: "disabled"
};
export { mentionDefaultProps, mentionEmits, mentionProps };
//# sourceMappingURL=mention.mjs.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,309 @@
import { defineComponent, computed, ref, openBlock, createElementBlock, normalizeClass, unref, createVNode, mergeProps, createSlots, renderList, withCtx, renderSlot, normalizeProps, guardReactiveProps, createElementVNode, normalizeStyle, withModifiers, nextTick } from 'vue';
import { pick } from 'lodash-unified';
import { ElInput } from '../../input/index.mjs';
import { ElTooltip } from '../../tooltip/index.mjs';
import { mentionProps, mentionEmits, mentionDefaultProps } from './mention.mjs';
import { getCursorPosition, getMentionCtx } from './helper.mjs';
import ElMentionDropdown from './mention-dropdown2.mjs';
import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
import { inputProps } from '../../input/src/input.mjs';
import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
import { useFormDisabled } from '../../form/src/hooks/use-form-common-props.mjs';
import { useId } from '../../../hooks/use-id/index.mjs';
import { useFocusController } from '../../../hooks/use-focus-controller/index.mjs';
import { UPDATE_MODEL_EVENT, INPUT_EVENT } from '../../../constants/event.mjs';
import { EVENT_CODE } from '../../../constants/aria.mjs';
import { isFunction } from '@vue/shared';
const __default__ = defineComponent({
name: "ElMention",
inheritAttrs: false
});
const _sfc_main = /* @__PURE__ */ defineComponent({
...__default__,
props: mentionProps,
emits: mentionEmits,
setup(__props, { expose, emit }) {
const props = __props;
const passInputProps = computed(() => pick(props, Object.keys(inputProps)));
const ns = useNamespace("mention");
const disabled = useFormDisabled();
const contentId = useId();
const elInputRef = ref();
const tooltipRef = ref();
const dropdownRef = ref();
const visible = ref(false);
const cursorStyle = ref();
const mentionCtx = ref();
const computedPlacement = computed(() => props.showArrow ? props.placement : `${props.placement}-start`);
const computedFallbackPlacements = computed(() => props.showArrow ? ["bottom", "top"] : ["bottom-start", "top-start"]);
const aliasProps = computed(() => ({
...mentionDefaultProps,
...props.props
}));
const mapOption = (option) => {
const base = {
label: option[aliasProps.value.label],
value: option[aliasProps.value.value],
disabled: option[aliasProps.value.disabled]
};
return { ...option, ...base };
};
const options = computed(() => props.options.map(mapOption));
const filteredOptions = computed(() => {
const { filterOption } = props;
if (!mentionCtx.value || !filterOption)
return options.value;
return options.value.filter((option) => filterOption(mentionCtx.value.pattern, option));
});
const dropdownVisible = computed(() => {
return visible.value && (!!filteredOptions.value.length || props.loading);
});
const hoveringId = computed(() => {
var _a;
return `${contentId.value}-${(_a = dropdownRef.value) == null ? void 0 : _a.hoveringIndex}`;
});
const handleInputChange = (value) => {
emit(UPDATE_MODEL_EVENT, value);
emit(INPUT_EVENT, value);
syncAfterCursorMove();
};
const handleInputKeyDown = (event) => {
var _a, _b, _c, _d;
if (!("code" in event) || ((_a = elInputRef.value) == null ? void 0 : _a.isComposing))
return;
switch (event.code) {
case EVENT_CODE.left:
case EVENT_CODE.right:
syncAfterCursorMove();
break;
case EVENT_CODE.up:
case EVENT_CODE.down:
if (!visible.value)
return;
event.preventDefault();
(_b = dropdownRef.value) == null ? void 0 : _b.navigateOptions(event.code === EVENT_CODE.up ? "prev" : "next");
break;
case EVENT_CODE.enter:
case EVENT_CODE.numpadEnter:
if (!visible.value)
return;
event.preventDefault();
if ((_c = dropdownRef.value) == null ? void 0 : _c.hoverOption) {
(_d = dropdownRef.value) == null ? void 0 : _d.selectHoverOption();
} else {
visible.value = false;
}
break;
case EVENT_CODE.esc:
if (!visible.value)
return;
event.preventDefault();
visible.value = false;
break;
case EVENT_CODE.backspace:
if (props.whole && mentionCtx.value) {
const { splitIndex, selectionEnd, pattern, prefixIndex, prefix } = mentionCtx.value;
const inputEl = getInputEl();
if (!inputEl)
return;
const inputValue = inputEl.value;
const matchOption = options.value.find((item) => item.value === pattern);
const isWhole = isFunction(props.checkIsWhole) ? props.checkIsWhole(pattern, prefix) : matchOption;
if (isWhole && splitIndex !== -1 && splitIndex + 1 === selectionEnd) {
event.preventDefault();
const newValue = inputValue.slice(0, prefixIndex) + inputValue.slice(splitIndex + 1);
emit(UPDATE_MODEL_EVENT, newValue);
emit(INPUT_EVENT, newValue);
emit("whole-remove", pattern, prefix);
const newSelectionEnd = prefixIndex;
nextTick(() => {
inputEl.selectionStart = newSelectionEnd;
inputEl.selectionEnd = newSelectionEnd;
syncDropdownVisible();
});
}
}
}
};
const { wrapperRef } = useFocusController(elInputRef, {
disabled,
afterFocus() {
syncAfterCursorMove();
},
beforeBlur(event) {
var _a;
return (_a = tooltipRef.value) == null ? void 0 : _a.isFocusInsideContent(event);
},
afterBlur() {
visible.value = false;
}
});
const handleInputMouseDown = () => {
syncAfterCursorMove();
};
const getOriginalOption = (mentionOption) => {
return props.options.find((option) => {
return mentionOption.value === option[aliasProps.value.value];
});
};
const handleSelect = (item) => {
if (!mentionCtx.value)
return;
const inputEl = getInputEl();
if (!inputEl)
return;
const inputValue = inputEl.value;
const { split } = props;
const newEndPart = inputValue.slice(mentionCtx.value.end);
const alreadySeparated = newEndPart.startsWith(split);
const newMiddlePart = `${item.value}${alreadySeparated ? "" : split}`;
const newValue = inputValue.slice(0, mentionCtx.value.start) + newMiddlePart + newEndPart;
emit(UPDATE_MODEL_EVENT, newValue);
emit(INPUT_EVENT, newValue);
emit("select", getOriginalOption(item), mentionCtx.value.prefix);
const newSelectionEnd = mentionCtx.value.start + newMiddlePart.length + (alreadySeparated ? 1 : 0);
nextTick(() => {
inputEl.selectionStart = newSelectionEnd;
inputEl.selectionEnd = newSelectionEnd;
inputEl.focus();
syncDropdownVisible();
});
};
const getInputEl = () => {
var _a, _b;
return props.type === "textarea" ? (_a = elInputRef.value) == null ? void 0 : _a.textarea : (_b = elInputRef.value) == null ? void 0 : _b.input;
};
const syncAfterCursorMove = () => {
setTimeout(() => {
syncCursor();
syncDropdownVisible();
nextTick(() => {
var _a;
return (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper();
});
}, 0);
};
const syncCursor = () => {
const inputEl = getInputEl();
if (!inputEl)
return;
const caretPosition = getCursorPosition(inputEl);
const inputRect = inputEl.getBoundingClientRect();
const wrapperRect = wrapperRef.value.getBoundingClientRect();
cursorStyle.value = {
position: "absolute",
width: 0,
height: `${caretPosition.height}px`,
left: `${caretPosition.left + inputRect.left - wrapperRect.left}px`,
top: `${caretPosition.top + inputRect.top - wrapperRect.top}px`
};
};
const syncDropdownVisible = () => {
const inputEl = getInputEl();
if (document.activeElement !== inputEl) {
visible.value = false;
return;
}
const { prefix, split } = props;
mentionCtx.value = getMentionCtx(inputEl, prefix, split);
if (mentionCtx.value && mentionCtx.value.splitIndex === -1) {
visible.value = true;
emit("search", mentionCtx.value.pattern, mentionCtx.value.prefix);
return;
}
visible.value = false;
};
expose({
input: elInputRef,
tooltip: tooltipRef,
dropdownVisible
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref_key: "wrapperRef",
ref: wrapperRef,
class: normalizeClass(unref(ns).b())
}, [
createVNode(unref(ElInput), mergeProps(mergeProps(unref(passInputProps), _ctx.$attrs), {
ref_key: "elInputRef",
ref: elInputRef,
"model-value": _ctx.modelValue,
disabled: unref(disabled),
role: unref(dropdownVisible) ? "combobox" : void 0,
"aria-activedescendant": unref(dropdownVisible) ? unref(hoveringId) || "" : void 0,
"aria-controls": unref(dropdownVisible) ? unref(contentId) : void 0,
"aria-expanded": unref(dropdownVisible) || void 0,
"aria-label": _ctx.ariaLabel,
"aria-autocomplete": unref(dropdownVisible) ? "none" : void 0,
"aria-haspopup": unref(dropdownVisible) ? "listbox" : void 0,
onInput: handleInputChange,
onKeydown: handleInputKeyDown,
onMousedown: handleInputMouseDown
}), createSlots({
_: 2
}, [
renderList(_ctx.$slots, (_, name) => {
return {
name,
fn: withCtx((slotProps) => [
renderSlot(_ctx.$slots, name, normalizeProps(guardReactiveProps(slotProps)))
])
};
})
]), 1040, ["model-value", "disabled", "role", "aria-activedescendant", "aria-controls", "aria-expanded", "aria-label", "aria-autocomplete", "aria-haspopup"]),
createVNode(unref(ElTooltip), {
ref_key: "tooltipRef",
ref: tooltipRef,
visible: unref(dropdownVisible),
"popper-class": [unref(ns).e("popper"), _ctx.popperClass],
"popper-options": _ctx.popperOptions,
placement: unref(computedPlacement),
"fallback-placements": unref(computedFallbackPlacements),
effect: "light",
pure: "",
offset: _ctx.offset,
"show-arrow": _ctx.showArrow
}, {
default: withCtx(() => [
createElementVNode("div", {
style: normalizeStyle(cursorStyle.value)
}, null, 4)
]),
content: withCtx(() => {
var _a;
return [
createVNode(ElMentionDropdown, {
ref_key: "dropdownRef",
ref: dropdownRef,
options: unref(filteredOptions),
disabled: unref(disabled),
loading: _ctx.loading,
"content-id": unref(contentId),
"aria-label": _ctx.ariaLabel,
onSelect: handleSelect,
onClick: withModifiers((_a = elInputRef.value) == null ? void 0 : _a.focus, ["stop"])
}, createSlots({
_: 2
}, [
renderList(_ctx.$slots, (_, name) => {
return {
name,
fn: withCtx((slotProps) => [
renderSlot(_ctx.$slots, name, normalizeProps(guardReactiveProps(slotProps)))
])
};
})
]), 1032, ["options", "disabled", "loading", "content-id", "aria-label", "onClick"])
];
}),
_: 3
}, 8, ["visible", "popper-class", "popper-options", "placement", "fallback-placements", "offset", "show-arrow"])
], 2);
};
}
});
var Mention = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "mention.vue"]]);
export { Mention as default };
//# sourceMappingURL=mention2.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
export type MentionOption = {
value?: string;
label?: string;
disabled?: boolean;
[key: string]: any;
};
export interface MentionCtx {
pattern: string;
start: number;
end: number;
prefix: string;
prefixIndex: number;
splitIndex: number;
selectionEnd: number;
}

View File

@@ -0,0 +1,2 @@
//# sourceMappingURL=types.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"types.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}

View File

@@ -0,0 +1,5 @@
import 'element-plus/es/components/base/style/css';
import 'element-plus/es/components/input/style/css';
import 'element-plus/es/components/tooltip/style/css';
import 'element-plus/es/components/scrollbar/style/css';
import 'element-plus/theme-chalk/el-mention.css';

View File

@@ -0,0 +1,6 @@
import '../../base/style/css.mjs';
import '../../input/style/css.mjs';
import '../../tooltip/style/css.mjs';
import '../../scrollbar/style/css.mjs';
import 'element-plus/theme-chalk/el-mention.css';
//# sourceMappingURL=css.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"css.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}

View File

@@ -0,0 +1,5 @@
import 'element-plus/es/components/base/style';
import 'element-plus/es/components/input/style';
import 'element-plus/es/components/tooltip/style';
import 'element-plus/es/components/scrollbar/style';
import 'element-plus/theme-chalk/src/mention.scss';

View File

@@ -0,0 +1,6 @@
import '../../base/style/index.mjs';
import '../../input/style/index.mjs';
import '../../tooltip/style/index.mjs';
import '../../scrollbar/style/index.mjs';
import 'element-plus/theme-chalk/src/mention.scss';
//# sourceMappingURL=index.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}