dadb5aa345d5c174565491684e25f172f94c57f0068a02e3e31d3f3f44f1518dd871fcba5363b6266b50e37472e7da5b3b32eafba8b8802272203af316acff 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var vue = require('vue');
  4. var lodashUnified = require('lodash-unified');
  5. var index$3 = require('../../input/index.js');
  6. var index$4 = require('../../tooltip/index.js');
  7. var mention = require('./mention.js');
  8. var helper = require('./helper.js');
  9. var mentionDropdown = require('./mention-dropdown2.js');
  10. var pluginVue_exportHelper = require('../../../_virtual/plugin-vue_export-helper.js');
  11. var input = require('../../input/src/input.js');
  12. var index = require('../../../hooks/use-namespace/index.js');
  13. var useFormCommonProps = require('../../form/src/hooks/use-form-common-props.js');
  14. var index$1 = require('../../../hooks/use-id/index.js');
  15. var index$2 = require('../../../hooks/use-focus-controller/index.js');
  16. var event = require('../../../constants/event.js');
  17. var aria = require('../../../constants/aria.js');
  18. var shared = require('@vue/shared');
  19. const __default__ = vue.defineComponent({
  20. name: "ElMention",
  21. inheritAttrs: false
  22. });
  23. const _sfc_main = /* @__PURE__ */ vue.defineComponent({
  24. ...__default__,
  25. props: mention.mentionProps,
  26. emits: mention.mentionEmits,
  27. setup(__props, { expose, emit }) {
  28. const props = __props;
  29. const passInputProps = vue.computed(() => lodashUnified.pick(props, Object.keys(input.inputProps)));
  30. const ns = index.useNamespace("mention");
  31. const disabled = useFormCommonProps.useFormDisabled();
  32. const contentId = index$1.useId();
  33. const elInputRef = vue.ref();
  34. const tooltipRef = vue.ref();
  35. const dropdownRef = vue.ref();
  36. const visible = vue.ref(false);
  37. const cursorStyle = vue.ref();
  38. const mentionCtx = vue.ref();
  39. const computedPlacement = vue.computed(() => props.showArrow ? props.placement : `${props.placement}-start`);
  40. const computedFallbackPlacements = vue.computed(() => props.showArrow ? ["bottom", "top"] : ["bottom-start", "top-start"]);
  41. const aliasProps = vue.computed(() => ({
  42. ...mention.mentionDefaultProps,
  43. ...props.props
  44. }));
  45. const mapOption = (option) => {
  46. const base = {
  47. label: option[aliasProps.value.label],
  48. value: option[aliasProps.value.value],
  49. disabled: option[aliasProps.value.disabled]
  50. };
  51. return { ...option, ...base };
  52. };
  53. const options = vue.computed(() => props.options.map(mapOption));
  54. const filteredOptions = vue.computed(() => {
  55. const { filterOption } = props;
  56. if (!mentionCtx.value || !filterOption)
  57. return options.value;
  58. return options.value.filter((option) => filterOption(mentionCtx.value.pattern, option));
  59. });
  60. const dropdownVisible = vue.computed(() => {
  61. return visible.value && (!!filteredOptions.value.length || props.loading);
  62. });
  63. const hoveringId = vue.computed(() => {
  64. var _a;
  65. return `${contentId.value}-${(_a = dropdownRef.value) == null ? void 0 : _a.hoveringIndex}`;
  66. });
  67. const handleInputChange = (value) => {
  68. emit(event.UPDATE_MODEL_EVENT, value);
  69. emit(event.INPUT_EVENT, value);
  70. syncAfterCursorMove();
  71. };
  72. const handleInputKeyDown = (event$1) => {
  73. var _a, _b, _c, _d;
  74. if (!("code" in event$1) || ((_a = elInputRef.value) == null ? void 0 : _a.isComposing))
  75. return;
  76. switch (event$1.code) {
  77. case aria.EVENT_CODE.left:
  78. case aria.EVENT_CODE.right:
  79. syncAfterCursorMove();
  80. break;
  81. case aria.EVENT_CODE.up:
  82. case aria.EVENT_CODE.down:
  83. if (!visible.value)
  84. return;
  85. event$1.preventDefault();
  86. (_b = dropdownRef.value) == null ? void 0 : _b.navigateOptions(event$1.code === aria.EVENT_CODE.up ? "prev" : "next");
  87. break;
  88. case aria.EVENT_CODE.enter:
  89. case aria.EVENT_CODE.numpadEnter:
  90. if (!visible.value)
  91. return;
  92. event$1.preventDefault();
  93. if ((_c = dropdownRef.value) == null ? void 0 : _c.hoverOption) {
  94. (_d = dropdownRef.value) == null ? void 0 : _d.selectHoverOption();
  95. } else {
  96. visible.value = false;
  97. }
  98. break;
  99. case aria.EVENT_CODE.esc:
  100. if (!visible.value)
  101. return;
  102. event$1.preventDefault();
  103. visible.value = false;
  104. break;
  105. case aria.EVENT_CODE.backspace:
  106. if (props.whole && mentionCtx.value) {
  107. const { splitIndex, selectionEnd, pattern, prefixIndex, prefix } = mentionCtx.value;
  108. const inputEl = getInputEl();
  109. if (!inputEl)
  110. return;
  111. const inputValue = inputEl.value;
  112. const matchOption = options.value.find((item) => item.value === pattern);
  113. const isWhole = shared.isFunction(props.checkIsWhole) ? props.checkIsWhole(pattern, prefix) : matchOption;
  114. if (isWhole && splitIndex !== -1 && splitIndex + 1 === selectionEnd) {
  115. event$1.preventDefault();
  116. const newValue = inputValue.slice(0, prefixIndex) + inputValue.slice(splitIndex + 1);
  117. emit(event.UPDATE_MODEL_EVENT, newValue);
  118. emit(event.INPUT_EVENT, newValue);
  119. emit("whole-remove", pattern, prefix);
  120. const newSelectionEnd = prefixIndex;
  121. vue.nextTick(() => {
  122. inputEl.selectionStart = newSelectionEnd;
  123. inputEl.selectionEnd = newSelectionEnd;
  124. syncDropdownVisible();
  125. });
  126. }
  127. }
  128. }
  129. };
  130. const { wrapperRef } = index$2.useFocusController(elInputRef, {
  131. disabled,
  132. afterFocus() {
  133. syncAfterCursorMove();
  134. },
  135. beforeBlur(event) {
  136. var _a;
  137. return (_a = tooltipRef.value) == null ? void 0 : _a.isFocusInsideContent(event);
  138. },
  139. afterBlur() {
  140. visible.value = false;
  141. }
  142. });
  143. const handleInputMouseDown = () => {
  144. syncAfterCursorMove();
  145. };
  146. const getOriginalOption = (mentionOption) => {
  147. return props.options.find((option) => {
  148. return mentionOption.value === option[aliasProps.value.value];
  149. });
  150. };
  151. const handleSelect = (item) => {
  152. if (!mentionCtx.value)
  153. return;
  154. const inputEl = getInputEl();
  155. if (!inputEl)
  156. return;
  157. const inputValue = inputEl.value;
  158. const { split } = props;
  159. const newEndPart = inputValue.slice(mentionCtx.value.end);
  160. const alreadySeparated = newEndPart.startsWith(split);
  161. const newMiddlePart = `${item.value}${alreadySeparated ? "" : split}`;
  162. const newValue = inputValue.slice(0, mentionCtx.value.start) + newMiddlePart + newEndPart;
  163. emit(event.UPDATE_MODEL_EVENT, newValue);
  164. emit(event.INPUT_EVENT, newValue);
  165. emit("select", getOriginalOption(item), mentionCtx.value.prefix);
  166. const newSelectionEnd = mentionCtx.value.start + newMiddlePart.length + (alreadySeparated ? 1 : 0);
  167. vue.nextTick(() => {
  168. inputEl.selectionStart = newSelectionEnd;
  169. inputEl.selectionEnd = newSelectionEnd;
  170. inputEl.focus();
  171. syncDropdownVisible();
  172. });
  173. };
  174. const getInputEl = () => {
  175. var _a, _b;
  176. return props.type === "textarea" ? (_a = elInputRef.value) == null ? void 0 : _a.textarea : (_b = elInputRef.value) == null ? void 0 : _b.input;
  177. };
  178. const syncAfterCursorMove = () => {
  179. setTimeout(() => {
  180. syncCursor();
  181. syncDropdownVisible();
  182. vue.nextTick(() => {
  183. var _a;
  184. return (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper();
  185. });
  186. }, 0);
  187. };
  188. const syncCursor = () => {
  189. const inputEl = getInputEl();
  190. if (!inputEl)
  191. return;
  192. const caretPosition = helper.getCursorPosition(inputEl);
  193. const inputRect = inputEl.getBoundingClientRect();
  194. const wrapperRect = wrapperRef.value.getBoundingClientRect();
  195. cursorStyle.value = {
  196. position: "absolute",
  197. width: 0,
  198. height: `${caretPosition.height}px`,
  199. left: `${caretPosition.left + inputRect.left - wrapperRect.left}px`,
  200. top: `${caretPosition.top + inputRect.top - wrapperRect.top}px`
  201. };
  202. };
  203. const syncDropdownVisible = () => {
  204. const inputEl = getInputEl();
  205. if (document.activeElement !== inputEl) {
  206. visible.value = false;
  207. return;
  208. }
  209. const { prefix, split } = props;
  210. mentionCtx.value = helper.getMentionCtx(inputEl, prefix, split);
  211. if (mentionCtx.value && mentionCtx.value.splitIndex === -1) {
  212. visible.value = true;
  213. emit("search", mentionCtx.value.pattern, mentionCtx.value.prefix);
  214. return;
  215. }
  216. visible.value = false;
  217. };
  218. expose({
  219. input: elInputRef,
  220. tooltip: tooltipRef,
  221. dropdownVisible
  222. });
  223. return (_ctx, _cache) => {
  224. return vue.openBlock(), vue.createElementBlock("div", {
  225. ref_key: "wrapperRef",
  226. ref: wrapperRef,
  227. class: vue.normalizeClass(vue.unref(ns).b())
  228. }, [
  229. vue.createVNode(vue.unref(index$3.ElInput), vue.mergeProps(vue.mergeProps(vue.unref(passInputProps), _ctx.$attrs), {
  230. ref_key: "elInputRef",
  231. ref: elInputRef,
  232. "model-value": _ctx.modelValue,
  233. disabled: vue.unref(disabled),
  234. role: vue.unref(dropdownVisible) ? "combobox" : void 0,
  235. "aria-activedescendant": vue.unref(dropdownVisible) ? vue.unref(hoveringId) || "" : void 0,
  236. "aria-controls": vue.unref(dropdownVisible) ? vue.unref(contentId) : void 0,
  237. "aria-expanded": vue.unref(dropdownVisible) || void 0,
  238. "aria-label": _ctx.ariaLabel,
  239. "aria-autocomplete": vue.unref(dropdownVisible) ? "none" : void 0,
  240. "aria-haspopup": vue.unref(dropdownVisible) ? "listbox" : void 0,
  241. onInput: handleInputChange,
  242. onKeydown: handleInputKeyDown,
  243. onMousedown: handleInputMouseDown
  244. }), vue.createSlots({
  245. _: 2
  246. }, [
  247. vue.renderList(_ctx.$slots, (_, name) => {
  248. return {
  249. name,
  250. fn: vue.withCtx((slotProps) => [
  251. vue.renderSlot(_ctx.$slots, name, vue.normalizeProps(vue.guardReactiveProps(slotProps)))
  252. ])
  253. };
  254. })
  255. ]), 1040, ["model-value", "disabled", "role", "aria-activedescendant", "aria-controls", "aria-expanded", "aria-label", "aria-autocomplete", "aria-haspopup"]),
  256. vue.createVNode(vue.unref(index$4.ElTooltip), {
  257. ref_key: "tooltipRef",
  258. ref: tooltipRef,
  259. visible: vue.unref(dropdownVisible),
  260. "popper-class": [vue.unref(ns).e("popper"), _ctx.popperClass],
  261. "popper-options": _ctx.popperOptions,
  262. placement: vue.unref(computedPlacement),
  263. "fallback-placements": vue.unref(computedFallbackPlacements),
  264. effect: "light",
  265. pure: "",
  266. offset: _ctx.offset,
  267. "show-arrow": _ctx.showArrow
  268. }, {
  269. default: vue.withCtx(() => [
  270. vue.createElementVNode("div", {
  271. style: vue.normalizeStyle(cursorStyle.value)
  272. }, null, 4)
  273. ]),
  274. content: vue.withCtx(() => {
  275. var _a;
  276. return [
  277. vue.createVNode(mentionDropdown["default"], {
  278. ref_key: "dropdownRef",
  279. ref: dropdownRef,
  280. options: vue.unref(filteredOptions),
  281. disabled: vue.unref(disabled),
  282. loading: _ctx.loading,
  283. "content-id": vue.unref(contentId),
  284. "aria-label": _ctx.ariaLabel,
  285. onSelect: handleSelect,
  286. onClick: vue.withModifiers((_a = elInputRef.value) == null ? void 0 : _a.focus, ["stop"])
  287. }, vue.createSlots({
  288. _: 2
  289. }, [
  290. vue.renderList(_ctx.$slots, (_, name) => {
  291. return {
  292. name,
  293. fn: vue.withCtx((slotProps) => [
  294. vue.renderSlot(_ctx.$slots, name, vue.normalizeProps(vue.guardReactiveProps(slotProps)))
  295. ])
  296. };
  297. })
  298. ]), 1032, ["options", "disabled", "loading", "content-id", "aria-label", "onClick"])
  299. ];
  300. }),
  301. _: 3
  302. }, 8, ["visible", "popper-class", "popper-options", "placement", "fallback-placements", "offset", "show-arrow"])
  303. ], 2);
  304. };
  305. }
  306. });
  307. var Mention = /* @__PURE__ */ pluginVue_exportHelper["default"](_sfc_main, [["__file", "mention.vue"]]);
  308. exports["default"] = Mention;
  309. //# sourceMappingURL=mention2.js.map