@shenjipo/mention-vue2 2.7.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";var $=Object.defineProperty;var y=Object.getOwnPropertySymbols;var q=Object.prototype.hasOwnProperty,b=Object.prototype.propertyIsEnumerable;var h=(n,e,t)=>e in n?$(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,M=(n,e)=>{for(var t in e||(e={}))q.call(e,t)&&h(n,t,e[t]);if(y)for(var t of y(e))b.call(e,t)&&h(n,t,e[t]);return n};var C=(n,e,t)=>new Promise((l,u)=>{var s=o=>{try{d(t.next(o))}catch(a){u(a)}},r=o=>{try{d(t.throw(o))}catch(a){u(a)}},d=o=>o.done?l(o.value):Promise.resolve(o.value).then(s,r);d((t=t.apply(n,e)).next())});Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const k=require("@shenjipo/mention-editor"),i=require("vue-demi"),v=require("@floating-ui/dom"),E=n=>n&&typeof n=="object"&&"default"in n?n:{default:n},w=E(k);function m(n,e,t,l,u,s,r,d){var o=typeof n=="function"?n.options:n;e&&(o.render=e,o.staticRenderFns=t,o._compiled=!0),l&&(o.functional=!0),s&&(o._scopeId="data-v-"+s);var a;if(r?(a=function(c){c=c||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,!c&&typeof __VUE_SSR_CONTEXT__!="undefined"&&(c=__VUE_SSR_CONTEXT__),u&&u.call(this,c),c&&c._registeredComponents&&c._registeredComponents.add(r)},o._ssrRegister=a):u&&(a=d?function(){u.call(this,(o.functional?this.parent:this).$root.$options.shadowRoot)}:u),a)if(o.functional){o._injectStyles=a;var f=o.render;o.render=function(g,p){return a.call(p),f(g,p)}}else{var _=o.beforeCreate;o.beforeCreate=_?[].concat(_,a):[a]}return{exports:n,options:o}}const R={name:"MEditorVue2",props:{value:{type:String,default:""},options:{type:Object,default:()=>({placeholder:"请输入内容,可粘贴图片到此处,按下/唤起快捷指令,",lineBreak:"enter"})}},emits:["input","fileReject","imageInput","deleteMention","enter"],setup(n,{emit:e,expose:t}){const l=i.ref(null),u=i.ref(null);i.provide("editor",l),i.onMounted(()=>{u.value&&(l.value=new w.default({element:u.value,content:n.value,placeholder:n.options.placeholder,onChange:r=>{e("input",r)},onFileInput:r=>{e("fileInput",r)},onMentionDelete(r){e("deleteMention",r)},lineBreak:n.options.lineBreak,onEnter:()=>{e("enter")}}))});const s=()=>{l.value.clear(),e("update:modelValue","")};return t({editor:l,clear:s}),{editor:l,editorRef:u,clear:s}}};var x=function(){var e=this,t=e._self._c;return t("div",{staticClass:"mention-editor-wrapper"},[e._t("header"),t("div",{ref:"editorRef",staticClass:"mention-editor"},[e.editor?e._t("default"):e._e()],2),e._t("footer")],2)},F=[],Q=m(R,x,F,!1,null,"c620f459",null,null);const S=Q.exports;const U={name:"SuggestionMenu",props:{items:{type:Array,required:!0},loadingState:{type:String,default:"idle"},selectedIndex:{type:Number,default:0}},methods:{handleItemClick(n){this.$emit("itemClick",n)}}};var D=function(){var e=this,t=e._self._c;return t("div",{staticClass:"bn-suggestion-menu"},[e.items.length?e._l(e.items,function(l,u){return t("div",{key:l.id,staticClass:"suggestion-menu-item",class:{active:u===e.selectedIndex},on:{mousedown:function(s){return s.preventDefault(),e.handleItemClick(l)}}},[e._v(" "+e._s(l.label)+" ")])}):t("div",{staticClass:"suggestion-menu-item disabled"},[e._v("无数据")])],2)},A=[],L=m(U,D,A,!1,null,"af9205e7",null,null);const N=L.exports;function V(n,e,t,l){const u=i.ref(0),s=r=>r.key==="ArrowUp"?(r.preventDefault(),t.value&&t.value.length&&(u.value=(u.value-1+t.value.length)%t.value.length),!0):r.key==="ArrowDown"?(r.preventDefault(),t.value&&t.value.length&&(u.value=(u.value+1)%t.value.length),!0):r.key==="Enter"&&!r.isComposing?(r.preventDefault(),t.value&&t.value.length&&l&&l(t.value[u.value]),!0):!1;return i.onMounted(()=>{n&&n.domElement&&n.domElement.addEventListener("keydown",s,!0)}),i.onBeforeUnmount(()=>{n&&n.domElement&&n.domElement.removeEventListener("keydown",s,!0)}),i.watch(()=>e,()=>{u.value=0}),u}function B(n,e,t,l=8){const u=i.ref(0);return i.watch([n,e],([s,r])=>{r!=null&&(s&&s.length>0?u.value=r.length:r.length-u.value>l&&t())}),{lastUsefulQueryLength:u}}const T={name:"SuggestionMenuWrapper",components:{SuggestionMenu:N},props:{query:{type:String,required:!0},getItems:{type:Function,required:!0},onItemClick:{type:Function},closeMenu:{type:Function,required:!0},clearQuery:{type:Function,required:!0},insertMention:{type:Function,required:!0}},setup(n){const e=i.ref([]),t=i.ref("idle"),l=i.ref(""),u=i.inject("editor"),s=o=>{n.closeMenu(),n.clearQuery(),n.insertMention(o)},r=V(u.value,n.query,e,s);B(e,l,n.closeMenu);const d=()=>{const o=n.query;l.value=n.query,t.value="loading",n.getItems(n.query).then(a=>{l.value===o&&(e.value=a,t.value="loaded")})};return i.onMounted(d),i.watch(()=>n.query,()=>{d()}),{items:e,loadingState:t,selectedIndex:r,onItemClickInternal:s}}};var W=function(){var e=this,t=e._self._c;return t("SuggestionMenu",{attrs:{items:e.items,"loading-state":e.loadingState,"selected-index":e.selectedIndex},on:{itemClick:e.onItemClickInternal}})},j=[],O=m(T,W,j,!1,null,"e4189e8f",null,null);const P=O.exports;function z(n,e,t,l={}){const u=i.ref(null),s=i.ref(null),r=i.ref({});let d=null;i.watch(e,c=>{c&&(u.value={getBoundingClientRect:()=>c},o())},{immediate:!0}),i.watch(n,c=>C(this,null,function*(){if(!c){f();return}yield i.nextTick(),!(!u.value||!s.value)&&(o(),a())}));const o=()=>{const c=u.value,g=s.value;!c||!g||v.computePosition(c,g,{placement:l.placement||"bottom-start",middleware:[v.offset(l.offset||8),v.flip(),v.shift({padding:8})]}).then(({x:p,y:I})=>{r.value={position:"absolute",left:`${p}px`,top:`${I}px`}})};function a(){!u.value||!s.value||(d=v.autoUpdate(u.value,s.value,o))}function f(){d&&(d(),d=null)}const _=i.computed(()=>M({display:"flex",zIndex:t},r.value));return{floatingRef:s,style:_}}const K={name:"SuggestionMenuController",components:{SuggestionMenuWrapper:P},props:{triggerCharacter:{type:String,required:!0},minQueryLength:{type:Number},getItems:{type:Function,required:!0},onItemClick:{type:Function}},setup(n){const e=i.inject("editor"),t=i.ref(null),l=i.computed(()=>{var _;const f=((_=t.value)==null?void 0:_.show)&&(!n.minQueryLength||t.value.ignoreQueryLength||!t.value.query.startsWith(" ")&&t.value.query.length>=n.minQueryLength);return f!=null?f:!1}),{floatingRef:u,style:s}=z(()=>l.value,()=>{var f;return((f=t.value)==null?void 0:f.referencePos)||null},2e3,{placement:"bottom-start",middleware:[v.offset(10),v.flip({mainAxis:!0,crossAxis:!1}),v.shift(),v.size({apply({availableHeight:f,elements:_}){Object.assign(_.floating.style,{maxHeight:`${f-10}px`})}})],onDismiss(){}});let r=null;return i.onMounted(()=>{r=e.value.suggestionMenus.onUpdate(n.triggerCharacter,f=>{t.value=f})}),i.onBeforeUnmount(()=>{r&&r()}),{state:t,floatingRef:u,style:s,showDom:l,closeMenu:()=>{e.value.suggestionMenus.closeMenu()},clearQuery:()=>{e.value.suggestionMenus.clearQuery()},insertMention:f=>{e.value.suggestionMenus.insertMention(f)}}}};var X=function(){var e=this,t=e._self._c;return e.showDom?t("div",{ref:"floatingRef",style:e.style},[t("SuggestionMenuWrapper",{attrs:{query:e.state.query,getItems:e.getItems,onItemClick:e.onItemClick,closeMenu:e.closeMenu,clearQuery:e.clearQuery,insertMention:e.insertMention}})],1):e._e()},H=[],G=m(K,X,H,!1,null,"f5b73a66",null,null);const J=G.exports;exports.MEditorVue2=S;exports.SuggestionMenuController=J;exports.default=S;
1
+ "use strict";var $=Object.defineProperty;var m=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var h=(n,e,t)=>e in n?$(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,y=(n,e)=>{for(var t in e||(e={}))w.call(e,t)&&h(n,t,e[t]);if(m)for(var t of m(e))E.call(e,t)&&h(n,t,e[t]);return n};var M=(n,e,t)=>new Promise((f,r)=>{var c=o=>{try{d(t.next(o))}catch(i){r(i)}},l=o=>{try{d(t.throw(o))}catch(i){r(i)}},d=o=>o.done?f(o.value):Promise.resolve(o.value).then(c,l);d((t=t.apply(n,e)).next())});Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const S=require("@shenjipo/mention-editor"),s=require("vue-demi"),p=require("@floating-ui/dom"),U=n=>n&&typeof n=="object"&&"default"in n?n:{default:n},q=U(S);function C(n,e,t,f,r,c,l,d){var o=typeof n=="function"?n.options:n;e&&(o.render=e,o.staticRenderFns=t,o._compiled=!0),f&&(o.functional=!0),c&&(o._scopeId="data-v-"+c);var i;if(l?(i=function(u){u=u||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,!u&&typeof __VUE_SSR_CONTEXT__!="undefined"&&(u=__VUE_SSR_CONTEXT__),r&&r.call(this,u),u&&u._registeredComponents&&u._registeredComponents.add(l)},o._ssrRegister=i):r&&(i=d?function(){r.call(this,(o.functional?this.parent:this).$root.$options.shadowRoot)}:r),i)if(o.functional){o._injectStyles=i;var a=o.render;o.render=function(v,g){return i.call(g),a(v,g)}}else{var _=o.beforeCreate;o.beforeCreate=_?[].concat(_,i):[i]}return{exports:n,options:o}}const Q={name:"MEditorVue2",props:{value:{type:String,default:""},options:{type:Object,default:()=>({placeholder:"请输入内容,可粘贴图片到此处,按下/唤起快捷指令,",lineBreak:"enter"})}},emits:["input","fileReject","imageInput","deleteMention","enter"],setup(n,{emit:e,expose:t}){const f=s.ref(null),r=s.ref(null);s.provide("editor",f),s.onMounted(()=>{r.value&&(f.value=new q.default({element:r.value,content:n.value,placeholder:n.options.placeholder,onChange:l=>{e("input",l)},onFileInput:l=>{e("fileInput",l)},onMentionDelete(l){e("deleteMention",l)},lineBreak:n.options.lineBreak,onEnter:()=>{e("enter")}}))});const c=()=>{f.value.clear(),e("update:modelValue","")};return t({editor:f,clear:c}),{editor:f,editorRef:r,clear:c}}};var V=function(){var e=this,t=e._self._c;return t("div",{staticClass:"mention-editor-wrapper"},[e._t("header"),t("div",{ref:"editorRef",staticClass:"mention-editor"},[e.editor?e._t("default"):e._e()],2),e._t("footer")],2)},D=[],T=C(Q,V,D,!1,null,"c620f459",null,null);const b=T.exports;function k(n,e,t,f={}){const r=s.ref(null),c=s.ref(null),l=s.ref({});let d=null;s.watch(e,u=>{u&&(r.value={getBoundingClientRect:()=>u},o())},{immediate:!0}),s.watch(n,u=>M(this,null,function*(){if(!u){a();return}yield s.nextTick(),!(!r.value||!c.value)&&(o(),i())}));const o=()=>{const u=r.value,v=c.value;!u||!v||p.computePosition(u,v,{placement:f.placement||"bottom-start",middleware:[p.offset(f.offset||8),p.flip(),p.shift({padding:8})]}).then(({x:g,y:R})=>{l.value={position:"absolute",left:`${g}px`,top:`${R}px`}})};function i(){!r.value||!c.value||(d=p.autoUpdate(r.value,c.value,o))}function a(){d&&(d(),d=null)}const _=s.computed(()=>y({zIndex:t},l.value));return{floatingRef:c,style:_}}const A={name:"SuggestionMenuController",props:{triggerCharacter:{type:String,required:!0},minQueryLength:{type:Number}},setup(n){const e=s.inject("editor"),t=s.ref(null),f=s.computed(()=>{var _;const a=((_=t.value)==null?void 0:_.show)&&(!n.minQueryLength||t.value.ignoreQueryLength||!t.value.query.startsWith(" ")&&t.value.query.length>=n.minQueryLength);return a!=null?a:!1}),{floatingRef:r,style:c}=k(()=>f.value,()=>{var a;return((a=t.value)==null?void 0:a.referencePos)||null},2e3,{placement:"bottom-start",middleware:[p.offset(10),p.flip({mainAxis:!0,crossAxis:!1}),p.shift(),p.size({apply({availableHeight:a,elements:_}){Object.assign(_.floating.style,{maxHeight:`${a-10}px`})}})],onDismiss(){}});let l=null;s.onMounted(()=>{l=e.value.suggestionMenus.onUpdate(n.triggerCharacter,a=>{t.value=a})}),s.onBeforeUnmount(()=>{l&&l()});const d=()=>{e.value.suggestionMenus.closeMenu()},o=()=>{e.value.suggestionMenus.clearQuery()},i=a=>{e.value.suggestionMenus.insertMention(a)};return{floatingRef:r,style:c,showDom:f,editor:e.value,state:t,closeMenu:d,clearQuery:o,insertMention:i}}};var B=function(){var e=this,t=e._self._c;return e.showDom?t("div",{ref:"floatingRef",style:e.style},[e._t("default",null,{query:e.state.query,editor:e.editor,closeMenu:e.closeMenu,clearQuery:e.clearQuery,insertMention:e.insertMention})],2):e._e()},O=[],P=C(A,B,O,!1,null,"5eadb932",null,null);const j=P.exports;exports.MEditorVue2=b;exports.SuggestionMenuController=j;exports.default=b;
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- .mention-editor-wrapper{border:1px solid #d9d9d9;padding:8px 12px;transition:border-color .2s,box-shadow .2s;border-radius:6px}.mention-editor-wrapper:focus-within{border-color:#409eff;box-shadow:0 0 0 2px #409eff33}.mention-editor-wrapper .mention-editor{min-height:80px}.mention-editor-wrapper .mention-editor .tiptap{outline:none;max-height:200px;overflow:auto}.mention-editor-wrapper .mention-editor .tiptap p{margin:0}.mention-editor-wrapper .mention-editor .tiptap p.is-editor-empty:before{content:attr(data-placeholder);color:#aaa;float:left;height:0;pointer-events:none}.mention-editor-wrapper .mention-editor .tiptap .mention{padding:2px 6px;border-radius:8px;color:#4971f5;background-color:#ecf5ff;display:inline-block;margin-right:4px}.mention-editor-wrapper .mention-editor .bn-suggestion-menu{width:180px;background-color:#fff;border-radius:8px;box-shadow:0 2px 12px #00000026;overflow:hidden;font-size:14px;padding:4px}.mention-editor-wrapper .mention-editor .bn-suggestion-menu .suggestion-menu-item{display:flex;align-items:center;padding:8px 12px;cursor:pointer;transition:background-color .2s}.mention-editor-wrapper .mention-editor .bn-suggestion-menu .suggestion-menu-item:hover{background-color:#f1f5f9}.mention-editor-wrapper .mention-editor .bn-suggestion-menu .suggestion-menu-item span{flex:1}.mention-editor-wrapper .mention-editor .bn-suggestion-menu .suggestion-menu-item.active{background-color:#f1f5f9}.mention-editor-wrapper .mention-editor .bn-suggestion-menu .suggestion-menu-item.disabled{background-color:unset;cursor:not-allowed}
1
+ .mention-editor-wrapper{border:1px solid #d9d9d9;padding:8px 12px;transition:border-color .2s,box-shadow .2s;border-radius:6px}.mention-editor-wrapper:focus-within{border-color:#409eff;box-shadow:0 0 0 2px #409eff33}.mention-editor-wrapper .mention-editor{min-height:80px}.mention-editor-wrapper .mention-editor .tiptap{outline:none;max-height:200px;overflow:auto}.mention-editor-wrapper .mention-editor .tiptap p{margin:0}.mention-editor-wrapper .mention-editor .tiptap p.is-editor-empty:before{content:attr(data-placeholder);color:#aaa;float:left;height:0;pointer-events:none}.mention-editor-wrapper .mention-editor .tiptap .mention{padding:2px 6px;border-radius:8px;color:#4971f5;background-color:#ecf5ff;display:inline-block;margin-right:4px}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,8BAA8B,CAAA;AACtD,OAAO,wBAAwB,MAAM,0DAA0D,CAAA;AAG/F,OAAO,EACH,WAAW,EACX,wBAAwB,GAC3B,CAAA;AACD,eAAe,WAAW,CAAA;AAE1B,OAAO,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,8BAA8B,CAAA;AACtD,OAAO,wBAAwB,MAAM,0DAA0D,CAAA;AAI/F,OAAO,EACH,WAAW,EACX,wBAAwB,GAE3B,CAAA;AACD,eAAe,WAAW,CAAA;AAE1B,OAAO,qBAAqB,CAAA"}
package/dist/index.esm.js CHANGED
@@ -1,63 +1,63 @@
1
- var x = Object.defineProperty;
2
- var h = Object.getOwnPropertySymbols;
3
- var w = Object.prototype.hasOwnProperty, F = Object.prototype.propertyIsEnumerable;
4
- var M = (n, e, t) => e in n ? x(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t, C = (n, e) => {
1
+ var Q = Object.defineProperty;
2
+ var g = Object.getOwnPropertySymbols;
3
+ var S = Object.prototype.hasOwnProperty, V = Object.prototype.propertyIsEnumerable;
4
+ var m = (o, e, t) => e in o ? Q(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t, h = (o, e) => {
5
5
  for (var t in e || (e = {}))
6
- w.call(e, t) && M(n, t, e[t]);
7
- if (h)
8
- for (var t of h(e))
9
- F.call(e, t) && M(n, t, e[t]);
10
- return n;
6
+ S.call(e, t) && m(o, t, e[t]);
7
+ if (g)
8
+ for (var t of g(e))
9
+ V.call(e, t) && m(o, t, e[t]);
10
+ return o;
11
11
  };
12
- var I = (n, e, t) => new Promise((o, u) => {
13
- var i = (l) => {
12
+ var y = (o, e, t) => new Promise((s, r) => {
13
+ var c = (n) => {
14
14
  try {
15
- d(t.next(l));
16
- } catch (s) {
17
- u(s);
15
+ f(t.next(n));
16
+ } catch (u) {
17
+ r(u);
18
18
  }
19
- }, r = (l) => {
19
+ }, l = (n) => {
20
20
  try {
21
- d(t.throw(l));
22
- } catch (s) {
23
- u(s);
21
+ f(t.throw(n));
22
+ } catch (u) {
23
+ r(u);
24
24
  }
25
- }, d = (l) => l.done ? o(l.value) : Promise.resolve(l.value).then(i, r);
26
- d((t = t.apply(n, e)).next());
25
+ }, f = (n) => n.done ? s(n.value) : Promise.resolve(n.value).then(c, l);
26
+ f((t = t.apply(o, e)).next());
27
27
  });
28
- import Q from "@shenjipo/mention-editor";
29
- import { ref as f, provide as U, onMounted as p, onBeforeUnmount as S, watch as v, inject as $, nextTick as D, computed as k } from "vue-demi";
30
- import { computePosition as A, offset as q, flip as b, shift as R, autoUpdate as L, size as N } from "@floating-ui/dom";
31
- function y(n, e, t, o, u, i, r, d) {
32
- var l = typeof n == "function" ? n.options : n;
33
- e && (l.render = e, l.staticRenderFns = t, l._compiled = !0), o && (l.functional = !0), i && (l._scopeId = "data-v-" + i);
34
- var s;
35
- if (r ? (s = function(a) {
36
- a = a || // cached call
28
+ import k from "@shenjipo/mention-editor";
29
+ import { ref as _, provide as q, onMounted as C, watch as M, nextTick as A, computed as R, inject as B, onBeforeUnmount as T } from "vue-demi";
30
+ import { computePosition as x, offset as $, flip as b, shift as w, autoUpdate as D, size as F } from "@floating-ui/dom";
31
+ function E(o, e, t, s, r, c, l, f) {
32
+ var n = typeof o == "function" ? o.options : o;
33
+ e && (n.render = e, n.staticRenderFns = t, n._compiled = !0), s && (n.functional = !0), c && (n._scopeId = "data-v-" + c);
34
+ var u;
35
+ if (l ? (u = function(i) {
36
+ i = i || // cached call
37
37
  this.$vnode && this.$vnode.ssrContext || // stateful
38
- this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext, !a && typeof __VUE_SSR_CONTEXT__ != "undefined" && (a = __VUE_SSR_CONTEXT__), u && u.call(this, a), a && a._registeredComponents && a._registeredComponents.add(r);
39
- }, l._ssrRegister = s) : u && (s = d ? function() {
40
- u.call(
38
+ this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext, !i && typeof __VUE_SSR_CONTEXT__ != "undefined" && (i = __VUE_SSR_CONTEXT__), r && r.call(this, i), i && i._registeredComponents && i._registeredComponents.add(l);
39
+ }, n._ssrRegister = u) : r && (u = f ? function() {
40
+ r.call(
41
41
  this,
42
- (l.functional ? this.parent : this).$root.$options.shadowRoot
42
+ (n.functional ? this.parent : this).$root.$options.shadowRoot
43
43
  );
44
- } : u), s)
45
- if (l.functional) {
46
- l._injectStyles = s;
47
- var c = l.render;
48
- l.render = function(g, m) {
49
- return s.call(m), c(g, m);
44
+ } : r), u)
45
+ if (n.functional) {
46
+ n._injectStyles = u;
47
+ var a = n.render;
48
+ n.render = function(p, v) {
49
+ return u.call(v), a(p, v);
50
50
  };
51
51
  } else {
52
- var _ = l.beforeCreate;
53
- l.beforeCreate = _ ? [].concat(_, s) : [s];
52
+ var d = n.beforeCreate;
53
+ n.beforeCreate = d ? [].concat(d, u) : [u];
54
54
  }
55
55
  return {
56
- exports: n,
57
- options: l
56
+ exports: o,
57
+ options: n
58
58
  };
59
59
  }
60
- const V = {
60
+ const I = {
61
61
  name: "MEditorVue2",
62
62
  props: {
63
63
  value: { type: String, default: "" },
@@ -70,249 +70,132 @@ const V = {
70
70
  }
71
71
  },
72
72
  emits: ["input", "fileReject", "imageInput", "deleteMention", "enter"],
73
- setup(n, { emit: e, expose: t }) {
74
- const o = f(null), u = f(null);
75
- U("editor", o), p(() => {
76
- u.value && (o.value = new Q({
77
- element: u.value,
78
- content: n.value,
79
- placeholder: n.options.placeholder,
80
- onChange: (r) => {
81
- e("input", r);
73
+ setup(o, { emit: e, expose: t }) {
74
+ const s = _(null), r = _(null);
75
+ q("editor", s), C(() => {
76
+ r.value && (s.value = new k({
77
+ element: r.value,
78
+ content: o.value,
79
+ placeholder: o.options.placeholder,
80
+ onChange: (l) => {
81
+ e("input", l);
82
82
  },
83
- onFileInput: (r) => {
84
- e("fileInput", r);
83
+ onFileInput: (l) => {
84
+ e("fileInput", l);
85
85
  },
86
- onMentionDelete(r) {
87
- e("deleteMention", r);
86
+ onMentionDelete(l) {
87
+ e("deleteMention", l);
88
88
  },
89
- lineBreak: n.options.lineBreak,
89
+ lineBreak: o.options.lineBreak,
90
90
  onEnter: () => {
91
91
  e("enter");
92
92
  }
93
93
  }));
94
94
  });
95
- const i = () => {
96
- o.value.clear(), e("update:modelValue", "");
95
+ const c = () => {
96
+ s.value.clear(), e("update:modelValue", "");
97
97
  };
98
- return t({ editor: o, clear: i }), {
99
- editor: o,
100
- editorRef: u,
101
- clear: i
98
+ return t({ editor: s, clear: c }), {
99
+ editor: s,
100
+ editorRef: r,
101
+ clear: c
102
102
  };
103
103
  }
104
104
  };
105
- var W = function() {
105
+ var L = function() {
106
106
  var e = this, t = e._self._c;
107
107
  return t("div", { staticClass: "mention-editor-wrapper" }, [e._t("header"), t("div", { ref: "editorRef", staticClass: "mention-editor" }, [e.editor ? e._t("default") : e._e()], 2), e._t("footer")], 2);
108
- }, B = [], T = /* @__PURE__ */ y(
109
- V,
110
- W,
111
- B,
112
- !1,
113
- null,
114
- "c620f459",
115
- null,
116
- null
117
- );
118
- const ce = T.exports;
119
- const O = {
120
- name: "SuggestionMenu",
121
- props: {
122
- items: { type: Array, required: !0 },
123
- loadingState: { type: String, default: "idle" },
124
- selectedIndex: { type: Number, default: 0 }
125
- },
126
- methods: {
127
- handleItemClick(n) {
128
- this.$emit("itemClick", n);
129
- }
130
- }
131
- };
132
- var P = function() {
133
- var e = this, t = e._self._c;
134
- return t("div", { staticClass: "bn-suggestion-menu" }, [e.items.length ? e._l(e.items, function(o, u) {
135
- return t("div", { key: o.id, staticClass: "suggestion-menu-item", class: { active: u === e.selectedIndex }, on: { mousedown: function(i) {
136
- return i.preventDefault(), e.handleItemClick(o);
137
- } } }, [e._v(" " + e._s(o.label) + " ")]);
138
- }) : t("div", { staticClass: "suggestion-menu-item disabled" }, [e._v("无数据")])], 2);
139
- }, j = [], z = /* @__PURE__ */ y(
108
+ }, O = [], P = /* @__PURE__ */ E(
109
+ I,
110
+ L,
140
111
  O,
141
- P,
142
- j,
143
- !1,
144
- null,
145
- "af9205e7",
146
- null,
147
- null
148
- );
149
- const K = z.exports;
150
- function X(n, e, t, o) {
151
- const u = f(0), i = (r) => r.key === "ArrowUp" ? (r.preventDefault(), t.value && t.value.length && (u.value = (u.value - 1 + t.value.length) % t.value.length), !0) : r.key === "ArrowDown" ? (r.preventDefault(), t.value && t.value.length && (u.value = (u.value + 1) % t.value.length), !0) : r.key === "Enter" && !r.isComposing ? (r.preventDefault(), t.value && t.value.length && o && o(t.value[u.value]), !0) : !1;
152
- return p(() => {
153
- n && n.domElement && n.domElement.addEventListener("keydown", i, !0);
154
- }), S(() => {
155
- n && n.domElement && n.domElement.removeEventListener("keydown", i, !0);
156
- }), v(
157
- () => e,
158
- () => {
159
- u.value = 0;
160
- }
161
- ), u;
162
- }
163
- function H(n, e, t, o = 8) {
164
- const u = f(0);
165
- return v(
166
- [n, e],
167
- ([i, r]) => {
168
- r != null && (i && i.length > 0 ? u.value = r.length : r.length - u.value > o && t());
169
- }
170
- ), {
171
- lastUsefulQueryLength: u
172
- };
173
- }
174
- const G = {
175
- name: "SuggestionMenuWrapper",
176
- components: {
177
- SuggestionMenu: K
178
- },
179
- props: {
180
- query: { type: String, required: !0 },
181
- getItems: { type: Function, required: !0 },
182
- onItemClick: { type: Function },
183
- closeMenu: { type: Function, required: !0 },
184
- clearQuery: { type: Function, required: !0 },
185
- insertMention: { type: Function, required: !0 }
186
- },
187
- setup(n) {
188
- const e = f([]), t = f("idle"), o = f(""), u = $("editor"), i = (l) => {
189
- n.closeMenu(), n.clearQuery(), n.insertMention(l);
190
- }, r = X(
191
- u.value,
192
- n.query,
193
- e,
194
- i
195
- );
196
- H(e, o, n.closeMenu);
197
- const d = () => {
198
- const l = n.query;
199
- o.value = n.query, t.value = "loading", n.getItems(n.query).then((s) => {
200
- o.value === l && (e.value = s, t.value = "loaded");
201
- });
202
- };
203
- return p(d), v(
204
- () => n.query,
205
- () => {
206
- d();
207
- }
208
- ), {
209
- items: e,
210
- loadingState: t,
211
- selectedIndex: r,
212
- onItemClickInternal: i
213
- };
214
- }
215
- };
216
- var J = function() {
217
- var e = this, t = e._self._c;
218
- return t("SuggestionMenu", { attrs: { items: e.items, "loading-state": e.loadingState, "selected-index": e.selectedIndex }, on: { itemClick: e.onItemClickInternal } });
219
- }, Y = [], Z = /* @__PURE__ */ y(
220
- G,
221
- J,
222
- Y,
223
112
  !1,
224
113
  null,
225
- "e4189e8f",
114
+ "c620f459",
226
115
  null,
227
116
  null
228
117
  );
229
- const ee = Z.exports;
230
- function te(n, e, t, o = {}) {
231
- const u = f(null), i = f(null), r = f({});
232
- let d = null;
233
- v(
118
+ const Y = P.exports;
119
+ function N(o, e, t, s = {}) {
120
+ const r = _(null), c = _(null), l = _({});
121
+ let f = null;
122
+ M(
234
123
  e,
235
- (a) => {
236
- a && (u.value = {
237
- getBoundingClientRect: () => a
238
- }, l());
124
+ (i) => {
125
+ i && (r.value = {
126
+ getBoundingClientRect: () => i
127
+ }, n());
239
128
  },
240
129
  { immediate: !0 }
241
- ), v(
242
- n,
243
- (a) => I(this, null, function* () {
244
- if (!a) {
245
- c();
130
+ ), M(
131
+ o,
132
+ (i) => y(this, null, function* () {
133
+ if (!i) {
134
+ a();
246
135
  return;
247
136
  }
248
- yield D(), !(!u.value || !i.value) && (l(), s());
137
+ yield A(), !(!r.value || !c.value) && (n(), u());
249
138
  })
250
139
  );
251
- const l = () => {
252
- const a = u.value, g = i.value;
253
- !a || !g || A(a, g, {
254
- placement: o.placement || "bottom-start",
140
+ const n = () => {
141
+ const i = r.value, p = c.value;
142
+ !i || !p || x(i, p, {
143
+ placement: s.placement || "bottom-start",
255
144
  middleware: [
256
- q(o.offset || 8),
145
+ $(s.offset || 8),
257
146
  b(),
258
- R({ padding: 8 })
147
+ w({ padding: 8 })
259
148
  ]
260
- }).then(({ x: m, y: E }) => {
261
- r.value = {
149
+ }).then(({ x: v, y: U }) => {
150
+ l.value = {
262
151
  position: "absolute",
263
- left: `${m}px`,
264
- top: `${E}px`
152
+ left: `${v}px`,
153
+ top: `${U}px`
265
154
  };
266
155
  });
267
156
  };
268
- function s() {
269
- !u.value || !i.value || (d = L(u.value, i.value, l));
157
+ function u() {
158
+ !r.value || !c.value || (f = D(r.value, c.value, n));
270
159
  }
271
- function c() {
272
- d && (d(), d = null);
160
+ function a() {
161
+ f && (f(), f = null);
273
162
  }
274
- const _ = k(() => C({
275
- display: "flex",
163
+ const d = R(() => h({
276
164
  zIndex: t
277
- }, r.value));
165
+ }, l.value));
278
166
  return {
279
- floatingRef: i,
280
- style: _
167
+ floatingRef: c,
168
+ style: d
281
169
  };
282
170
  }
283
- const ne = {
171
+ const j = {
284
172
  name: "SuggestionMenuController",
285
- components: {
286
- SuggestionMenuWrapper: ee
287
- },
288
173
  props: {
289
174
  triggerCharacter: { type: String, required: !0 },
290
- minQueryLength: { type: Number },
291
- getItems: { type: Function, required: !0 },
292
- onItemClick: { type: Function }
175
+ minQueryLength: { type: Number }
293
176
  },
294
- setup(n) {
295
- const e = $("editor"), t = f(null), o = k(() => {
296
- var _;
297
- const c = ((_ = t.value) == null ? void 0 : _.show) && (!n.minQueryLength || t.value.ignoreQueryLength || !t.value.query.startsWith(" ") && t.value.query.length >= n.minQueryLength);
298
- return c != null ? c : !1;
299
- }), { floatingRef: u, style: i } = te(
300
- () => o.value,
177
+ setup(o) {
178
+ const e = B("editor"), t = _(null), s = R(() => {
179
+ var d;
180
+ const a = ((d = t.value) == null ? void 0 : d.show) && (!o.minQueryLength || t.value.ignoreQueryLength || !t.value.query.startsWith(" ") && t.value.query.length >= o.minQueryLength);
181
+ return a != null ? a : !1;
182
+ }), { floatingRef: r, style: c } = N(
183
+ () => s.value,
301
184
  () => {
302
- var c;
303
- return ((c = t.value) == null ? void 0 : c.referencePos) || null;
185
+ var a;
186
+ return ((a = t.value) == null ? void 0 : a.referencePos) || null;
304
187
  },
305
188
  2e3,
306
189
  {
307
190
  placement: "bottom-start",
308
191
  middleware: [
309
- q(10),
192
+ $(10),
310
193
  b({ mainAxis: !0, crossAxis: !1 }),
311
- R(),
312
- N({
313
- apply({ availableHeight: c, elements: _ }) {
314
- Object.assign(_.floating.style, {
315
- maxHeight: `${c - 10}px`
194
+ w(),
195
+ F({
196
+ apply({ availableHeight: a, elements: d }) {
197
+ Object.assign(d.floating.style, {
198
+ maxHeight: `${a - 10}px`
316
199
  });
317
200
  }
318
201
  })
@@ -321,49 +204,52 @@ const ne = {
321
204
  }
322
205
  }
323
206
  );
324
- let r = null;
325
- return p(() => {
326
- r = e.value.suggestionMenus.onUpdate(
327
- n.triggerCharacter,
328
- (c) => {
329
- t.value = c;
207
+ let l = null;
208
+ C(() => {
209
+ l = e.value.suggestionMenus.onUpdate(
210
+ o.triggerCharacter,
211
+ (a) => {
212
+ t.value = a;
330
213
  }
331
214
  );
332
- }), S(() => {
333
- r && r();
334
- }), {
215
+ }), T(() => {
216
+ l && l();
217
+ });
218
+ const f = () => {
219
+ e.value.suggestionMenus.closeMenu();
220
+ }, n = () => {
221
+ e.value.suggestionMenus.clearQuery();
222
+ }, u = (a) => {
223
+ e.value.suggestionMenus.insertMention(a);
224
+ };
225
+ return {
226
+ floatingRef: r,
227
+ style: c,
228
+ showDom: s,
229
+ editor: e.value,
335
230
  state: t,
336
- floatingRef: u,
337
- style: i,
338
- showDom: o,
339
- closeMenu: () => {
340
- e.value.suggestionMenus.closeMenu();
341
- },
342
- clearQuery: () => {
343
- e.value.suggestionMenus.clearQuery();
344
- },
345
- insertMention: (c) => {
346
- e.value.suggestionMenus.insertMention(c);
347
- }
231
+ closeMenu: f,
232
+ clearQuery: n,
233
+ insertMention: u
348
234
  };
349
235
  }
350
236
  };
351
- var ue = function() {
237
+ var z = function() {
352
238
  var e = this, t = e._self._c;
353
- return e.showDom ? t("div", { ref: "floatingRef", style: e.style }, [t("SuggestionMenuWrapper", { attrs: { query: e.state.query, getItems: e.getItems, onItemClick: e.onItemClick, closeMenu: e.closeMenu, clearQuery: e.clearQuery, insertMention: e.insertMention } })], 1) : e._e();
354
- }, re = [], le = /* @__PURE__ */ y(
355
- ne,
356
- ue,
357
- re,
239
+ return e.showDom ? t("div", { ref: "floatingRef", style: e.style }, [e._t("default", null, { query: e.state.query, editor: e.editor, closeMenu: e.closeMenu, clearQuery: e.clearQuery, insertMention: e.insertMention })], 2) : e._e();
240
+ }, W = [], X = /* @__PURE__ */ E(
241
+ j,
242
+ z,
243
+ W,
358
244
  !1,
359
245
  null,
360
- "f5b73a66",
246
+ "5eadb932",
361
247
  null,
362
248
  null
363
249
  );
364
- const de = le.exports;
250
+ const Z = X.exports;
365
251
  export {
366
- ce as MEditorVue2,
367
- de as SuggestionMenuController,
368
- ce as default
252
+ Y as MEditorVue2,
253
+ Z as SuggestionMenuController,
254
+ Y as default
369
255
  };
@@ -4,4 +4,15 @@ export type MEditorVue2Type = Vue & {
4
4
  editor: MEditor;
5
5
  clear: () => void;
6
6
  };
7
+ export interface SuggestionItem {
8
+ id: string;
9
+ label: string;
10
+ }
11
+ export interface SuggestionMenuProps {
12
+ editor: MEditor;
13
+ query: string;
14
+ closeMenu: () => void;
15
+ clearQuery: () => void;
16
+ insertMention: (item: SuggestionItem) => void;
17
+ }
7
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAA;AAC9C,OAAO,GAAG,MAAM,KAAK,CAAA;AAErB,MAAM,MAAM,eAAe,GAAG,GAAG,GAAG;IAChC,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAA;AAC9C,OAAO,GAAG,MAAM,KAAK,CAAA;AAGrB,MAAM,MAAM,eAAe,GAAG,GAAG,GAAG;IAChC,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,aAAa,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;CAChD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shenjipo/mention-vue2",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -18,7 +18,8 @@
18
18
  }
19
19
  },
20
20
  "files": [
21
- "dist"
21
+ "dist",
22
+ "src"
22
23
  ],
23
24
  "publishConfig": {
24
25
  "access": "public"
@@ -27,7 +28,7 @@
27
28
  "@floating-ui/dom": "^1.1.9",
28
29
  "vue": "^2.7.7",
29
30
  "vue-demi": "^0.14.10",
30
- "@shenjipo/mention-editor": "2.7.0"
31
+ "@shenjipo/mention-editor": "2.8.0"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@types/node": "^16.11.45",
@@ -0,0 +1,45 @@
1
+ .mention-editor-wrapper {
2
+ border: 1px solid #d9d9d9; // 默认边框颜色
3
+ padding: 8px 12px; // 内边距
4
+ transition:
5
+ border-color 0.2s,
6
+ box-shadow 0.2s; // 平滑过渡
7
+ border-radius: 6px;
8
+
9
+ &:focus-within {
10
+ border-color: #409eff; // 高亮颜色
11
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); // 柔和高亮光晕
12
+ }
13
+
14
+ .mention-editor {
15
+ min-height: 80px;
16
+
17
+ .tiptap {
18
+ outline: none;
19
+ max-height: 200px;
20
+ overflow: auto;
21
+ p {
22
+ margin: 0;
23
+ }
24
+
25
+ p.is-editor-empty::before {
26
+ content: attr(data-placeholder);
27
+ color: #aaa;
28
+ float: left;
29
+ height: 0;
30
+ pointer-events: none;
31
+ }
32
+
33
+ .mention {
34
+ padding: 2px 6px;
35
+ border-radius: 8px;
36
+ color: #4971f5;
37
+ background-color: #ecf5ff;
38
+ display: inline-block;
39
+ margin-right: 4px;
40
+ }
41
+ }
42
+
43
+
44
+ }
45
+ }
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <div class="mention-editor-wrapper">
3
+ <slot name="header"></slot>
4
+ <div ref="editorRef" class="mention-editor">
5
+ <slot v-if="editor"></slot>
6
+ </div>
7
+ <slot name="footer"></slot>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ import MEditor from '@shenjipo/mention-editor'
13
+ import { ref, onMounted, provide } from 'vue-demi'
14
+
15
+ export default {
16
+ name: 'MEditorVue2',
17
+ props: {
18
+ value: { type: String, default: '' },
19
+ options: {
20
+ type: Object,
21
+ default: () => ({
22
+ placeholder: '请输入内容,可粘贴图片到此处,按下/唤起快捷指令,',
23
+ lineBreak: 'enter',
24
+ }),
25
+ },
26
+ },
27
+ emits: ['input', 'fileReject', 'imageInput', 'deleteMention', 'enter'],
28
+ setup(props, { emit, expose }) {
29
+ const editor = ref(null)
30
+ const editorRef = ref(null)
31
+
32
+ provide('editor', editor)
33
+
34
+ onMounted(() => {
35
+ if (editorRef.value) {
36
+ editor.value = new MEditor({
37
+ element: editorRef.value,
38
+ content: props.value,
39
+ placeholder: props.options.placeholder,
40
+ onChange: (val) => {
41
+ emit('input', val)
42
+ },
43
+ onFileInput: (payload) => {
44
+ emit('fileInput', payload)
45
+ },
46
+ onMentionDelete(item) {
47
+ emit('deleteMention', item)
48
+ },
49
+ lineBreak: props.options.lineBreak,
50
+ onEnter: () => {
51
+ emit('enter')
52
+ },
53
+ })
54
+ }
55
+ })
56
+
57
+ const clear = () => {
58
+ editor.value.clear()
59
+ emit('update:modelValue', '')
60
+ }
61
+
62
+ expose({ editor, clear })
63
+
64
+ return {
65
+ editor,
66
+ editorRef,
67
+ clear,
68
+ }
69
+ },
70
+ }
71
+ </script>
72
+
73
+ <style scoped></style>
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <div v-if="showDom" ref="floatingRef" :style="style">
3
+ <slot :query="state.query" :editor="editor" :closeMenu="closeMenu" :clearQuery="clearQuery"
4
+ :insertMention="insertMention">
5
+ </slot>
6
+ </div>
7
+ </template>
8
+
9
+ <script>
10
+ import { ref, computed, onMounted, onBeforeUnmount, inject } from 'vue-demi'
11
+ import { useUIElementPositioning } from '@/hooks/useUIElementPositioning'
12
+ import { offset, flip, shift, size } from '@floating-ui/dom'
13
+
14
+ export default {
15
+ name: 'SuggestionMenuController',
16
+ props: {
17
+ triggerCharacter: { type: String, required: true },
18
+ minQueryLength: { type: Number },
19
+ },
20
+
21
+ setup(props) {
22
+ const editor = inject('editor')
23
+ const state = ref(null)
24
+
25
+ const showDom = computed(() => {
26
+ const res = state.value?.show &&
27
+ (!props.minQueryLength ||
28
+ state.value.ignoreQueryLength ||
29
+ (!state.value.query.startsWith(' ') &&
30
+ state.value.query.length >= props.minQueryLength))
31
+ return res ?? false
32
+ })
33
+
34
+ const { floatingRef, style } = useUIElementPositioning(
35
+ () => showDom.value,
36
+ () => state.value?.referencePos || null,
37
+ 2000,
38
+ {
39
+ placement: 'bottom-start',
40
+ middleware: [
41
+ offset(10),
42
+ flip({ mainAxis: true, crossAxis: false }),
43
+ shift(),
44
+ size({
45
+ apply({ availableHeight, elements }) {
46
+ Object.assign(elements.floating.style, {
47
+ maxHeight: `${availableHeight - 10}px`,
48
+ })
49
+ },
50
+ }),
51
+ ],
52
+ onDismiss() {
53
+ // 可以触发关闭逻辑
54
+ },
55
+ }
56
+ )
57
+
58
+ let unsubscribe = null
59
+ onMounted(() => {
60
+ unsubscribe = editor.value.suggestionMenus.onUpdate(
61
+ props.triggerCharacter,
62
+ (newState) => {
63
+ state.value = newState
64
+ }
65
+ )
66
+ })
67
+
68
+ onBeforeUnmount(() => {
69
+ unsubscribe && unsubscribe()
70
+ })
71
+
72
+ const closeMenu = () => {
73
+ editor.value.suggestionMenus.closeMenu()
74
+ }
75
+ const clearQuery = () => {
76
+ editor.value.suggestionMenus.clearQuery()
77
+ }
78
+ const insertMention = (item) => {
79
+ editor.value.suggestionMenus.insertMention(item)
80
+ }
81
+
82
+ return {
83
+ floatingRef,
84
+ style,
85
+ showDom,
86
+ editor: editor.value,
87
+ state,
88
+ closeMenu,
89
+ clearQuery,
90
+ insertMention,
91
+ }
92
+ },
93
+ }
94
+ </script>
95
+
96
+ <style scoped></style>
@@ -0,0 +1,55 @@
1
+ import { ref, watch, onMounted, onBeforeUnmount } from 'vue-demi'
2
+
3
+ export function useSuggestionMenuKeyboardNavigation(editor, query, items, onItemClick) {
4
+ const selectedIndex = ref(0)
5
+
6
+ const handleMenuNavigationKeys = (event) => {
7
+ if (event.key === 'ArrowUp') {
8
+ event.preventDefault()
9
+ if (items.value && items.value.length) {
10
+ selectedIndex.value = (selectedIndex.value - 1 + items.value.length) % items.value.length
11
+ }
12
+ return true
13
+ }
14
+
15
+ if (event.key === 'ArrowDown') {
16
+ event.preventDefault()
17
+ if (items.value && items.value.length) {
18
+ selectedIndex.value = (selectedIndex.value + 1) % items.value.length
19
+ }
20
+ return true
21
+ }
22
+
23
+ if (event.key === 'Enter' && !event.isComposing) {
24
+ event.preventDefault()
25
+ if (items.value && items.value.length) {
26
+ onItemClick && onItemClick(items.value[selectedIndex.value])
27
+ }
28
+ return true
29
+ }
30
+
31
+ return false
32
+ }
33
+
34
+ onMounted(() => {
35
+ if (editor && editor.domElement) {
36
+ editor.domElement.addEventListener('keydown', handleMenuNavigationKeys, true)
37
+ }
38
+ })
39
+
40
+ onBeforeUnmount(() => {
41
+ if (editor && editor.domElement) {
42
+ editor.domElement.removeEventListener('keydown', handleMenuNavigationKeys, true)
43
+ }
44
+ })
45
+
46
+ // query 变化时重置选中索引
47
+ watch(
48
+ () => query,
49
+ () => {
50
+ selectedIndex.value = 0
51
+ }
52
+ )
53
+
54
+ return selectedIndex
55
+ }
@@ -0,0 +1,81 @@
1
+ import { ref, computed, watch, nextTick } from 'vue-demi'
2
+ import { computePosition, autoUpdate, offset, flip, shift } from '@floating-ui/dom'
3
+
4
+ export function useUIElementPositioning(show, referencePos, zIndex, options = {}) {
5
+ const reference = ref(null)
6
+ const floatingRef = ref(null)
7
+ const floatingStyles = ref({})
8
+ let cleanupAutoUpdate = null
9
+
10
+ watch(
11
+ referencePos,
12
+ (pos) => {
13
+ if (!pos) return
14
+ reference.value = {
15
+ getBoundingClientRect: () => pos,
16
+ }
17
+ updatePosition()
18
+ },
19
+ { immediate: true }
20
+ )
21
+
22
+ watch(
23
+ show,
24
+ async (visible) => {
25
+ if (!visible) {
26
+ stopAutoUpdate()
27
+ return
28
+ }
29
+ await nextTick()
30
+ if (!reference.value || !floatingRef.value) return
31
+ updatePosition()
32
+ startAutoUpdate()
33
+ }
34
+ )
35
+
36
+
37
+ const updatePosition = () => {
38
+
39
+ const refEl = reference.value
40
+ const floatEl = floatingRef.value
41
+ if (!refEl || !floatEl) return
42
+
43
+ // computePosition 支持虚拟元素
44
+ computePosition(refEl, floatEl, {
45
+ placement: options.placement || 'bottom-start',
46
+ middleware: [
47
+ offset(options.offset || 8),
48
+ flip(),
49
+ shift({ padding: 8 }),
50
+ ],
51
+ }).then(({ x, y }) => {
52
+ floatingStyles.value = {
53
+ position: 'absolute',
54
+ left: `${x}px`,
55
+ top: `${y}px`,
56
+ }
57
+ })
58
+ }
59
+
60
+ function startAutoUpdate() {
61
+ if (!reference.value || !floatingRef.value) return
62
+ cleanupAutoUpdate = autoUpdate(reference.value, floatingRef.value, updatePosition)
63
+ }
64
+
65
+ function stopAutoUpdate() {
66
+ if (cleanupAutoUpdate) {
67
+ cleanupAutoUpdate()
68
+ cleanupAutoUpdate = null
69
+ }
70
+ }
71
+
72
+ const style = computed(() => ({
73
+ zIndex,
74
+ ...floatingStyles.value,
75
+ }))
76
+
77
+ return {
78
+ floatingRef: floatingRef,
79
+ style,
80
+ }
81
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ import MEditorVue2 from './components/MEditorVue2.vue'
2
+ import SuggestionMenuController from './components/SuggestionMenu/SuggestionMenuController.vue'
3
+
4
+
5
+ // 导出组件
6
+ export {
7
+ MEditorVue2,
8
+ SuggestionMenuController,
9
+
10
+ }
11
+ export default MEditorVue2
12
+
13
+ import './assets/index.scss'
@@ -0,0 +1,4 @@
1
+ declare module '*.vue' {
2
+ import Vue from 'vue'
3
+ export default Vue
4
+ }
@@ -0,0 +1,21 @@
1
+ import MEditor from "@shenjipo/mention-editor"
2
+ import Vue from "vue"
3
+
4
+
5
+ export type MEditorVue2Type = Vue & {
6
+ editor: MEditor
7
+ clear: () => void
8
+ }
9
+
10
+ export interface SuggestionItem {
11
+ id: string
12
+ label: string
13
+ }
14
+
15
+ export interface SuggestionMenuProps {
16
+ editor: MEditor
17
+ query: string
18
+ closeMenu: () => void
19
+ clearQuery: () => void
20
+ insertMention: (item: SuggestionItem) => void
21
+ }