@shenjipo/mention-editor 2.6.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.d.mts CHANGED
@@ -71,6 +71,12 @@ declare class MentionDeletePlugin {
71
71
  constructor(editor: MEditor, onMentionDelete?: (item: MentionItem) => void);
72
72
  }
73
73
 
74
+ type EnterMode = 'enter' | 'shift+enter';
75
+ declare class ShiftEnterPlugin {
76
+ readonly plugin: Plugin;
77
+ constructor(editor: MEditor, onEnter?: () => void);
78
+ }
79
+
74
80
  interface MentionEditorOptions {
75
81
  element: HTMLElement;
76
82
  onChange: (text: string) => void;
@@ -78,11 +84,15 @@ interface MentionEditorOptions {
78
84
  onFileInput?: (file: File) => void;
79
85
  content?: string;
80
86
  onMentionDelete?: (item: MentionItem) => void;
87
+ onEnter?: () => void;
88
+ lineBreak?: EnterMode;
81
89
  }
82
90
  declare class MEditor {
91
+ options: MentionEditorOptions;
83
92
  _tiptapEditor: Editor;
84
93
  readonly suggestionMenus: SuggestionMenuProseMirrorPlugin;
85
94
  readonly mentionDeletePlugin: MentionDeletePlugin;
95
+ readonly shiftEnterPlugin: ShiftEnterPlugin;
86
96
  constructor(options: MentionEditorOptions);
87
97
  dispatch(tr: Transaction): void;
88
98
  inserMentionBlock(item: MentionItem): void;
package/dist/index.d.ts CHANGED
@@ -71,6 +71,12 @@ declare class MentionDeletePlugin {
71
71
  constructor(editor: MEditor, onMentionDelete?: (item: MentionItem) => void);
72
72
  }
73
73
 
74
+ type EnterMode = 'enter' | 'shift+enter';
75
+ declare class ShiftEnterPlugin {
76
+ readonly plugin: Plugin;
77
+ constructor(editor: MEditor, onEnter?: () => void);
78
+ }
79
+
74
80
  interface MentionEditorOptions {
75
81
  element: HTMLElement;
76
82
  onChange: (text: string) => void;
@@ -78,11 +84,15 @@ interface MentionEditorOptions {
78
84
  onFileInput?: (file: File) => void;
79
85
  content?: string;
80
86
  onMentionDelete?: (item: MentionItem) => void;
87
+ onEnter?: () => void;
88
+ lineBreak?: EnterMode;
81
89
  }
82
90
  declare class MEditor {
91
+ options: MentionEditorOptions;
83
92
  _tiptapEditor: Editor;
84
93
  readonly suggestionMenus: SuggestionMenuProseMirrorPlugin;
85
94
  readonly mentionDeletePlugin: MentionDeletePlugin;
95
+ readonly shiftEnterPlugin: ShiftEnterPlugin;
86
96
  constructor(options: MentionEditorOptions);
87
97
  dispatch(tr: Transaction): void;
88
98
  inserMentionBlock(item: MentionItem): void;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var K=Object.create;var m=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var H=(r,t,e)=>t in r?m(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var $=(r,t)=>{for(var e in t)m(r,e,{get:t[e],enumerable:!0})},T=(r,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of R(t))!A.call(r,i)&&i!==e&&m(r,i,{get:()=>t[i],enumerable:!(n=Q(t,i))||n.enumerable});return r};var h=(r,t,e)=>(e=r!=null?K(U(r)):{},T(t||!r||!r.__esModule?m(e,"default",{value:r,enumerable:!0}):e,r)),V=r=>T(m({},"__esModule",{value:!0}),r);var s=(r,t,e)=>H(r,typeof t!="symbol"?t+"":t,e);var G={};$(G,{MEditor:()=>p,default:()=>j});module.exports=V(G);var M=require("@tiptap/core");var x=h(require("@tiptap/extension-document")),I=h(require("@tiptap/extension-paragraph")),k=h(require("@tiptap/extension-text")),v=[x.default,I.default,k.default];var D=h(require("@tiptap/extension-history")),B=h(require("@tiptap/extension-placeholder"));var w=require("@tiptap/core"),N=require("prosemirror-state"),_=w.Extension.create({name:"imageInput",addOptions(){return{onFileInput:void 0}},addProseMirrorPlugins(){let r=async t=>{var e,n;(n=(e=this.options).onFileInput)==null||n.call(e,t)};return[new N.Plugin({props:{handlePaste:(t,e)=>{var i;let n=(i=e.clipboardData)==null?void 0:i.items;if(!n)return!1;for(let o of n){if(o.kind!=="file")continue;let l=o.getAsFile();if(l)return r(l),!0}return!1},handleDrop:(t,e)=>{var i;let n=(i=e.dataTransfer)==null?void 0:i.files;return!n||n.length===0?!1:(r(n[0]),!0)}}})]}});var F=require("@tiptap/core"),E=require("prosemirror-state"),g=require("prosemirror-view");var f=class{constructor(){s(this,"callbacks",{})}on(t,e){return this.callbacks[t]||(this.callbacks[t]=[]),this.callbacks[t].push(e),()=>this.off(t,e)}emit(t,...e){let n=this.callbacks[t];n&&n.forEach(i=>i.apply(this,e))}off(t,e){let n=this.callbacks[t];n&&(e?this.callbacks[t]=n.filter(i=>i!==e):delete this.callbacks[t])}removeAllListeners(){this.callbacks={}}};var c=new E.PluginKey("SuggestionMenuPlugin"),z=(0,F.findParentNode)(r=>r.type.name==="blockContainer"),C=class{constructor(t,e){this.editor=t;s(this,"pluginState");s(this,"state");s(this,"emitUpdate");s(this,"rootEl");s(this,"closeMenu",()=>{this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(c,null))});s(this,"clearQuery",()=>{this.pluginState!==void 0&&this.editor._tiptapEditor.chain().focus().deleteRange({from:this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),to:this.editor._tiptapEditor.state.selection.from}).run()});s(this,"insertMention",t=>{this.editor._tiptapEditor.chain().focus().insertContent({type:"mention",attrs:t}).insertContent(" ").run()});this.pluginState=void 0,this.emitUpdate=n=>{var i;if(!this.state)throw new Error("Attempting to update uninitialized suggestions menu");e(n,{...this.state,ignoreQueryLength:(i=this.pluginState)==null?void 0:i.ignoreQueryLength})},setTimeout(()=>{this.rootEl=this.editor._tiptapEditor.view.root})}update(t,e){var u;let n=c.getState(e),i=c.getState(t.state),o=n===void 0&&i!==void 0,l=n!==void 0&&i===void 0;if(!o&&!(n!==void 0&&i!==void 0)&&!l)return;if(this.pluginState=l?n:i,l||!this.editor.isEditable){this.state.show=!1,this.emitUpdate(this.pluginState.triggerCharacter);return}let a=(u=this.rootEl)==null?void 0:u.querySelector(`[data-decoration-id="${this.pluginState.decorationId}"]`);this.editor.isEditable&&a&&(this.state={show:!0,referencePos:a.getBoundingClientRect(),query:this.pluginState.query},this.emitUpdate(this.pluginState.triggerCharacter))}destroy(){}getReplaceRange(){if(!this.pluginState)return null;let t=this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),e=this.editor._tiptapEditor.state.selection.from;return{from:t,to:e}}},y=class extends f{constructor(e){super();s(this,"view");s(this,"plugin");s(this,"triggerCharacters",[]);s(this,"addTriggerCharacter",e=>{this.triggerCharacters.push(e)});s(this,"removeTriggerCharacter",e=>{this.triggerCharacters=this.triggerCharacters.filter(n=>n!==e)});s(this,"closeMenu",()=>this.view.closeMenu());s(this,"clearQuery",()=>this.view.clearQuery());s(this,"insertMention",e=>this.view.insertMention(e));let n=this.triggerCharacters;this.plugin=new E.Plugin({key:c,view:()=>(this.view=new C(e,(i,o)=>{this.emit(`update ${i}`,o)}),this.view),state:{init(){},apply(i,o,l,d){var P;let a=i.getMeta(c);if(typeof a=="object"&&a!==null&&o===void 0)return{triggerCharacter:a.triggerCharacter,deleteTriggerCharacter:a.deleteTriggerCharacter!==!1,queryStartPos:((P=i.selection)==null?void 0:P.from)||d.selection.from,query:"",decorationId:`id_${Math.floor(Math.random()*4294967295)}`,ignoreQueryLength:a==null?void 0:a.ignoreQueryLength};if(o===void 0)return o;if(d.selection.from!==d.selection.to||a===null||i.getMeta("focus")||i.getMeta("blur")||i.getMeta("pointer")||o.triggerCharacter!==void 0&&d.selection.from<o.queryStartPos)return;let u={...o};return u.query=d.doc.textBetween(o.queryStartPos,d.selection.from),u}},props:{handleTextInput(i,o,l,d){let a=this.getState(i.state);return n.includes(d)&&a===void 0?(i.dispatch(i.state.tr.insertText(d).scrollIntoView().setMeta(c,{triggerCharacter:d})),!0):!1},decorations(i){let o=this.getState(i);if(o===void 0)return null;if(!o.deleteTriggerCharacter){let l=z(i.selection);if(l)return g.DecorationSet.create(i.doc,[g.Decoration.node(l.pos,l.pos+l.node.nodeSize,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":o.decorationId})])}return g.DecorationSet.create(i.doc,[g.Decoration.inline(o.queryStartPos-o.triggerCharacter.length,o.queryStartPos,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":o.decorationId})])}}})}onUpdate(e,n){return this.triggerCharacters.includes(e)||this.addTriggerCharacter(e),this.on(`update ${e}`,n)}get shown(){var e,n;return((n=(e=this.view)==null?void 0:e.state)==null?void 0:n.show)||!1}};var q=require("@tiptap/core"),L=q.Node.create({name:"mention",inline:!0,group:"inline",atom:!0,selectable:!1,addAttributes(){return{id:{default:null},label:{default:null}}},parseHTML(){return[{tag:'span[data-type="mention"]'}]},renderHTML({node:r}){return["span",{class:"mention","data-type":"mention","data-id":r.attrs.id,"data-label":r.attrs.label,contenteditable:"false"},r.attrs.label]},renderText({node:r}){return""}});function O(r,t){r._tiptapEditor.chain().insertContent({type:"mention",attrs:{id:t.id,label:t.label}}).run()}var S=require("prosemirror-state");var b=class{constructor(t,e){s(this,"plugin");this.plugin=new S.Plugin({key:new S.PluginKey("mention-delete"),appendTransaction(n,i,o){if(!n.some(a=>a.docChanged))return null;let l=new Map,d=new Set;i.doc.descendants(a=>{a.type.name==="mention"&&a.attrs.id&&l.set(a.attrs.id,a.attrs)}),o.doc.descendants(a=>{a.type.name==="mention"&&a.attrs.id&&d.add(a.attrs.id)});for(let[a,u]of l.entries())d.has(a)||e==null||e({id:u.id,label:u.label})}})}};var p=class{constructor(t){s(this,"_tiptapEditor");s(this,"suggestionMenus");s(this,"mentionDeletePlugin");this.suggestionMenus=new y(this),this.mentionDeletePlugin=new b(this,t.onMentionDelete);let e=M.Extension.create({name:"MEditorUIExtension",addProseMirrorPlugins:()=>[this.suggestionMenus.plugin,this.mentionDeletePlugin.plugin]});this._tiptapEditor=new M.Editor({element:t.element,content:t.content||"",extensions:[...v,D.default.configure({depth:100,newGroupDelay:500}),L,B.default.configure({placeholder:t.placeholder||"\u8BF7\u8F93\u5165...",emptyEditorClass:"is-editor-empty"}),_.configure({onFileInput:t.onFileInput}),e],onUpdate:({editor:n})=>{t.onChange(n.getText())}})}dispatch(t){this._tiptapEditor.view.dispatch(t)}inserMentionBlock(t){O(this,t)}get isEditable(){return this._tiptapEditor.isEditable===void 0?!0:this._tiptapEditor.isEditable}get domElement(){return this._tiptapEditor.view.dom}clear(){this._tiptapEditor.commands.clearContent(!0),this._tiptapEditor.commands.focus()}getAllMentionBlocks(){let t=[];return this._tiptapEditor.state.doc.descendants((n,i)=>{var o,l;n.type.name==="mention"&&t.push({id:(o=n.attrs.id)!=null?o:null,label:(l=n.attrs.label)!=null?l:null})}),t}};var j=p;0&&(module.exports={MEditor});
1
+ var V=Object.create;var m=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var W=(r,t,e)=>t in r?m(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var J=(r,t)=>{for(var e in t)m(r,e,{get:t[e],enumerable:!0})},I=(r,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of z(t))!G.call(r,i)&&i!==e&&m(r,i,{get:()=>t[i],enumerable:!(n=$(t,i))||n.enumerable});return r};var c=(r,t,e)=>(e=r!=null?V(j(r)):{},I(t||!r||!r.__esModule?m(e,"default",{value:r,enumerable:!0}):e,r)),X=r=>I(m({},"__esModule",{value:!0}),r);var a=(r,t,e)=>W(r,typeof t!="symbol"?t+"":t,e);var et={};J(et,{MEditor:()=>f,default:()=>tt});module.exports=X(et);var C=require("@tiptap/core");var v=c(require("@tiptap/extension-document")),_=c(require("@tiptap/extension-paragraph")),N=c(require("@tiptap/extension-text")),F=c(require("@tiptap/extension-hard-break")),q=[v.default,_.default,N.default,F.default];var U=c(require("@tiptap/extension-history")),A=c(require("@tiptap/extension-placeholder"));var K=require("@tiptap/core"),B=require("prosemirror-state"),D=K.Extension.create({name:"imageInput",addOptions(){return{onFileInput:void 0}},addProseMirrorPlugins(){let r=async t=>{var e,n;(n=(e=this.options).onFileInput)==null||n.call(e,t)};return[new B.Plugin({props:{handlePaste:(t,e)=>{var i;let n=(i=e.clipboardData)==null?void 0:i.items;if(!n)return!1;for(let o of n){if(o.kind!=="file")continue;let l=o.getAsFile();if(l)return r(l),!0}return!1},handleDrop:(t,e)=>{var i;let n=(i=e.dataTransfer)==null?void 0:i.files;return!n||n.length===0?!1:(r(n[0]),!0)}}})]}});var O=require("@tiptap/core"),S=require("prosemirror-state"),p=require("prosemirror-view");var E=class{constructor(){a(this,"callbacks",{})}on(t,e){return this.callbacks[t]||(this.callbacks[t]=[]),this.callbacks[t].push(e),()=>this.off(t,e)}emit(t,...e){let n=this.callbacks[t];n&&n.forEach(i=>i.apply(this,e))}off(t,e){let n=this.callbacks[t];n&&(e?this.callbacks[t]=n.filter(i=>i!==e):delete this.callbacks[t])}removeAllListeners(){this.callbacks={}}};var g=new S.PluginKey("SuggestionMenuPlugin"),Y=(0,O.findParentNode)(r=>r.type.name==="blockContainer"),T=class{constructor(t,e){this.editor=t;a(this,"pluginState");a(this,"state");a(this,"emitUpdate");a(this,"rootEl");a(this,"closeMenu",()=>{this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(g,null))});a(this,"clearQuery",()=>{this.pluginState!==void 0&&this.editor._tiptapEditor.chain().focus().deleteRange({from:this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),to:this.editor._tiptapEditor.state.selection.from}).run()});a(this,"insertMention",t=>{this.editor._tiptapEditor.chain().focus().insertContent({type:"mention",attrs:t}).insertContent(" ").run()});this.pluginState=void 0,this.emitUpdate=n=>{var i;if(!this.state)throw new Error("Attempting to update uninitialized suggestions menu");e(n,{...this.state,ignoreQueryLength:(i=this.pluginState)==null?void 0:i.ignoreQueryLength})},setTimeout(()=>{this.rootEl=this.editor._tiptapEditor.view.root})}update(t,e){var d;let n=g.getState(e),i=g.getState(t.state),o=n===void 0&&i!==void 0,l=n!==void 0&&i===void 0;if(!o&&!(n!==void 0&&i!==void 0)&&!l)return;if(this.pluginState=l?n:i,l||!this.editor.isEditable){this.state.show=!1,this.emitUpdate(this.pluginState.triggerCharacter);return}let s=(d=this.rootEl)==null?void 0:d.querySelector(`[data-decoration-id="${this.pluginState.decorationId}"]`);this.editor.isEditable&&s&&(this.state={show:!0,referencePos:s.getBoundingClientRect(),query:this.pluginState.query},this.emitUpdate(this.pluginState.triggerCharacter))}destroy(){}getReplaceRange(){if(!this.pluginState)return null;let t=this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),e=this.editor._tiptapEditor.state.selection.from;return{from:t,to:e}}},y=class extends E{constructor(e){super();a(this,"view");a(this,"plugin");a(this,"triggerCharacters",[]);a(this,"addTriggerCharacter",e=>{this.triggerCharacters.push(e)});a(this,"removeTriggerCharacter",e=>{this.triggerCharacters=this.triggerCharacters.filter(n=>n!==e)});a(this,"closeMenu",()=>this.view.closeMenu());a(this,"clearQuery",()=>this.view.clearQuery());a(this,"insertMention",e=>this.view.insertMention(e));let n=this.triggerCharacters;this.plugin=new S.Plugin({key:g,view:()=>(this.view=new T(e,(i,o)=>{this.emit(`update ${i}`,o)}),this.view),state:{init(){},apply(i,o,l,u){var h;let s=i.getMeta(g);if(typeof s=="object"&&s!==null&&o===void 0)return{triggerCharacter:s.triggerCharacter,deleteTriggerCharacter:s.deleteTriggerCharacter!==!1,queryStartPos:((h=i.selection)==null?void 0:h.from)||u.selection.from,query:"",decorationId:`id_${Math.floor(Math.random()*4294967295)}`,ignoreQueryLength:s==null?void 0:s.ignoreQueryLength};if(o===void 0)return o;if(u.selection.from!==u.selection.to||s===null||i.getMeta("focus")||i.getMeta("blur")||i.getMeta("pointer")||o.triggerCharacter!==void 0&&u.selection.from<o.queryStartPos)return;let d={...o};return d.query=u.doc.textBetween(o.queryStartPos,u.selection.from),d}},props:{handleTextInput(i,o,l,u){let s=this.getState(i.state);return n.includes(u)&&s===void 0?(i.dispatch(i.state.tr.insertText(u).scrollIntoView().setMeta(g,{triggerCharacter:u})),!0):!1},decorations(i){let o=this.getState(i);if(o===void 0)return null;if(!o.deleteTriggerCharacter){let l=Y(i.selection);if(l)return p.DecorationSet.create(i.doc,[p.Decoration.node(l.pos,l.pos+l.node.nodeSize,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":o.decorationId})])}return p.DecorationSet.create(i.doc,[p.Decoration.inline(o.queryStartPos-o.triggerCharacter.length,o.queryStartPos,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":o.decorationId})])}}})}onUpdate(e,n){return this.triggerCharacters.includes(e)||this.addTriggerCharacter(e),this.on(`update ${e}`,n)}get shown(){var e,n;return((n=(e=this.view)==null?void 0:e.state)==null?void 0:n.show)||!1}};var L=require("@tiptap/core"),Q=L.Node.create({name:"mention",inline:!0,group:"inline",atom:!0,selectable:!1,addAttributes(){return{id:{default:null},label:{default:null}}},parseHTML(){return[{tag:'span[data-type="mention"]'}]},renderHTML({node:r}){return["span",{class:"mention","data-type":"mention","data-id":r.attrs.id,"data-label":r.attrs.label,contenteditable:"false"},r.attrs.label]},renderText({node:r}){return""}});function R(r,t){r._tiptapEditor.chain().insertContent({type:"mention",attrs:{id:t.id,label:t.label}}).run()}var M=require("prosemirror-state");var b=class{constructor(t,e){a(this,"plugin");this.plugin=new M.Plugin({key:new M.PluginKey("mention-delete"),appendTransaction(n,i,o){if(!n.some(s=>s.docChanged))return null;let l=new Map,u=new Set;i.doc.descendants(s=>{s.type.name==="mention"&&s.attrs.id&&l.set(s.attrs.id,s.attrs)}),o.doc.descendants(s=>{s.type.name==="mention"&&s.attrs.id&&u.add(s.attrs.id)});for(let[s,d]of l.entries())u.has(s)||e==null||e({id:d.id,label:d.label})}})}};var x=require("prosemirror-state");var Z=new x.PluginKey("ShiftEnterPluginKey"),P=class{constructor(t,e){a(this,"plugin");this.plugin=new x.Plugin({key:Z,props:{handleKeyDown(n,i){var d,h;if(i.key!=="Enter")return!1;let o=(d=t.options.lineBreak)!=null?d:"enter",l=i.shiftKey,u=o==="enter"&&l||o==="shift+enter"&&!l,s=!u;if(u)return(h=t.suggestionMenus)!=null&&h.shown?!1:e?(i.preventDefault(),e(),!0):!1;if(s){i.preventDefault();let{state:k,dispatch:H}=n,{hard_break:w}=k.schema.nodes;return w?(H(k.tr.replaceSelectionWith(w.create()).scrollIntoView()),!0):!1}return!1}}})}};var f=class{constructor(t){a(this,"options");a(this,"_tiptapEditor");a(this,"suggestionMenus");a(this,"mentionDeletePlugin");a(this,"shiftEnterPlugin");this.options=t,this.suggestionMenus=new y(this),this.mentionDeletePlugin=new b(this,t.onMentionDelete),this.shiftEnterPlugin=new P(this,t.onEnter);let e=C.Extension.create({name:"MEditorUIExtension",addProseMirrorPlugins:()=>[this.suggestionMenus.plugin,this.mentionDeletePlugin.plugin,this.shiftEnterPlugin.plugin]});this._tiptapEditor=new C.Editor({element:t.element,content:t.content||"",extensions:[...q,U.default.configure({depth:100,newGroupDelay:500}),Q,A.default.configure({placeholder:t.placeholder||"\u8BF7\u8F93\u5165...",emptyEditorClass:"is-editor-empty"}),D.configure({onFileInput:t.onFileInput}),e],onUpdate:({editor:n})=>{t.onChange(n.getText())}})}dispatch(t){this._tiptapEditor.view.dispatch(t)}inserMentionBlock(t){R(this,t)}get isEditable(){return this._tiptapEditor.isEditable===void 0?!0:this._tiptapEditor.isEditable}get domElement(){return this._tiptapEditor.view.dom}clear(){this._tiptapEditor.commands.clearContent(!0),this._tiptapEditor.commands.focus()}getAllMentionBlocks(){let t=[];return this._tiptapEditor.state.doc.descendants((n,i)=>{var o,l;n.type.name==="mention"&&t.push({id:(o=n.attrs.id)!=null?o:null,label:(l=n.attrs.label)!=null?l:null})}),t}};var tt=f;0&&(module.exports={MEditor});
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/editor.ts","../src/schema/base.ts","../src/extensions/FileInput/FileInput.ts","../src/extensions/SuggestionMenu/SuggestionPlugin.ts","../src/utils/EventEmitter.ts","../src/blocks/MentionBlock.ts","../src/api/InsertMentionBlock.ts","../src/extensions/MentionDeletePlugin/MentionDeletePlugin.ts"],"sourcesContent":["import MEditor from \"./editor\";\n\nexport * from \"./extensions/SuggestionMenu/types\"\nexport * from \"./extensions/FileInput/types\"\n\nexport { MEditor }\nexport default MEditor","import { Editor, Extension } from '@tiptap/core'\nimport { baseExtensions } from './schema/base'\nimport History from '@tiptap/extension-history'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { FileInputExtension } from './extensions/FileInput/FileInput'\nimport { Transaction } from 'prosemirror-state'\nimport { SuggestionMenuProseMirrorPlugin } from './extensions/SuggestionMenu/SuggestionPlugin'\nimport { MentionBlock } from './blocks/MentionBlock'\nimport { type MentionItem } from './extensions/SuggestionMenu/types'\nimport { InsertMentionBlock } from './api/InsertMentionBlock'\nimport { MentionDeletePlugin } from './extensions/MentionDeletePlugin/MentionDeletePlugin'\n\nexport interface MentionEditorOptions {\n element: HTMLElement\n onChange: (text: string) => void\n placeholder?: string\n onFileInput?: (file: File) => void\n content?: string\n onMentionDelete?: (item: MentionItem) => void\n}\n\n\nexport default class MEditor {\n _tiptapEditor: Editor\n public readonly suggestionMenus: SuggestionMenuProseMirrorPlugin\n public readonly mentionDeletePlugin: MentionDeletePlugin\n\n constructor(options: MentionEditorOptions) {\n this.suggestionMenus = new SuggestionMenuProseMirrorPlugin(this)\n this.mentionDeletePlugin = new MentionDeletePlugin(this, options.onMentionDelete)\n\n const MEditorUIExtension = Extension.create({\n name: 'MEditorUIExtension',\n addProseMirrorPlugins: () => {\n return [\n this.suggestionMenus.plugin,\n this.mentionDeletePlugin.plugin,\n ]\n },\n })\n\n this._tiptapEditor = new Editor({\n element: options.element,\n content: options.content || '',\n extensions: [\n ...baseExtensions,\n History.configure({\n depth: 100,\n newGroupDelay: 500,\n }),\n MentionBlock,\n Placeholder.configure({\n placeholder: options.placeholder || '请输入...',\n emptyEditorClass: 'is-editor-empty'\n }),\n FileInputExtension.configure({\n onFileInput: options.onFileInput,\n }),\n MEditorUIExtension,\n ],\n onUpdate: ({ editor }) => {\n options.onChange(editor.getText())\n }\n })\n }\n\n\n dispatch(tr: Transaction) {\n this._tiptapEditor.view.dispatch(tr)\n }\n\n public inserMentionBlock(item: MentionItem) {\n InsertMentionBlock(this, item)\n // this._tiptapEditor\n // .chain()\n // .focus()\n // .insertContent({\n // type: 'mention',\n // attrs: item\n // })\n // .insertContent(' ')\n // .run()\n }\n\n public get isEditable(): boolean {\n return this._tiptapEditor.isEditable === undefined ? true : this._tiptapEditor.isEditable\n }\n\n public get domElement() {\n return this._tiptapEditor.view.dom as HTMLDivElement\n }\n\n public clear() {\n this._tiptapEditor.commands.clearContent(true)\n this._tiptapEditor.commands.focus()\n }\n\n public getAllMentionBlocks(): Array<MentionItem> {\n const mentions: Array<MentionItem> = []\n\n const doc = this._tiptapEditor.state.doc\n\n doc.descendants((node, pos) => {\n if (node.type.name === 'mention') {\n mentions.push({\n id: node.attrs.id ?? null,\n label: node.attrs.label ?? null,\n })\n }\n })\n\n return mentions\n }\n}\n","import Document from '@tiptap/extension-document'\nimport Paragraph from '@tiptap/extension-paragraph'\nimport Text from '@tiptap/extension-text'\n\nexport const baseExtensions = [\n Document,\n Paragraph,\n Text,\n]\n","import { Extension } from '@tiptap/core'\nimport { Plugin } from 'prosemirror-state'\nimport { FileInputOptions } from './types'\n\nexport const FileInputExtension = Extension.create<FileInputOptions>({\n name: 'imageInput',\n\n addOptions() {\n return {\n onFileInput: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n const handleFile = async (file: File) => {\n this.options.onFileInput?.(file)\n }\n\n return [\n new Plugin({\n props: {\n handlePaste: (_, event) => {\n const items = event.clipboardData?.items\n if (!items) return false\n\n for (const item of items) {\n if (item.kind !== 'file') continue\n const file = item.getAsFile()\n if (!file) continue\n\n handleFile(file)\n return true\n }\n\n return false\n },\n\n handleDrop: (_, event) => {\n const files = event.dataTransfer?.files\n if (!files || files.length === 0) return false\n\n handleFile(files[0])\n return true\n },\n },\n }),\n ]\n },\n})\n","import { findParentNode } from '@tiptap/core'\nimport { EditorState, Plugin, PluginKey } from 'prosemirror-state'\nimport { Decoration, DecorationSet, EditorView } from 'prosemirror-view'\nimport MEditor from '../../editor'\nimport { EventEmitter } from '../../utils/EventEmitter'\nimport { SuggestionMenuState, MentionItem } from './types'\n\ntype SuggestionPluginState =\n | {\n triggerCharacter: string\n deleteTriggerCharacter: boolean\n queryStartPos: number\n query: string\n decorationId: string\n ignoreQueryLength?: boolean\n }\n | undefined\n\nexport const suggestionMenuPluginKey = new PluginKey('SuggestionMenuPlugin')\nconst findBlock = findParentNode(node => node.type.name === 'blockContainer')\n\nclass SuggestionMenuView {\n pluginState: SuggestionPluginState\n public state?: SuggestionMenuState\n public emitUpdate: (triggerCharacter: string) => void\n private rootEl?: Document | ShadowRoot\n\n constructor(\n private readonly editor: MEditor,\n emitUpdate: (menuName: string, state: SuggestionMenuState) => void\n ) {\n this.pluginState = undefined\n\n this.emitUpdate = (menuName: string) => {\n if (!this.state) {\n throw new Error('Attempting to update uninitialized suggestions menu')\n }\n emitUpdate(menuName, {\n ...this.state,\n ignoreQueryLength: this.pluginState?.ignoreQueryLength,\n })\n }\n setTimeout(() => {\n this.rootEl = this.editor._tiptapEditor.view.root\n })\n\n }\n\n update(view: EditorView, prevState: EditorState) {\n\n const prev: SuggestionPluginState = suggestionMenuPluginKey.getState(prevState)\n const next: SuggestionPluginState = suggestionMenuPluginKey.getState(view.state)\n\n \n const started = prev === undefined && next !== undefined\n const stopped = prev !== undefined && next === undefined\n const changed = prev !== undefined && next !== undefined\n\n \n if (!started && !changed && !stopped) {\n return\n }\n\n this.pluginState = stopped ? prev : next\n\n if (stopped || !this.editor.isEditable) {\n\n this.state!.show = false\n this.emitUpdate(this.pluginState!.triggerCharacter)\n\n return\n }\n\n const decorationNode = this.rootEl?.querySelector(`[data-decoration-id=\"${this.pluginState!.decorationId}\"]`)\n\n if (this.editor.isEditable && decorationNode) {\n\n this.state = {\n show: true,\n referencePos: decorationNode.getBoundingClientRect(),\n query: this.pluginState!.query,\n }\n\n this.emitUpdate(this.pluginState!.triggerCharacter!)\n }\n }\n\n destroy() {\n\n }\n\n closeMenu = () => {\n this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(suggestionMenuPluginKey, null))\n }\n\n clearQuery = () => {\n if (this.pluginState === undefined) {\n return\n }\n\n this.editor._tiptapEditor\n .chain()\n .focus()\n .deleteRange({\n from:\n this.pluginState.queryStartPos! -\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter!.length : 0),\n to: this.editor._tiptapEditor.state.selection.from,\n })\n .run()\n }\n\n insertMention = (item: MentionItem) => {\n this.editor._tiptapEditor\n .chain()\n .focus()\n .insertContent({\n type: 'mention',\n attrs: item\n })\n .insertContent(' ')\n .run()\n }\n\n getReplaceRange() {\n if (!this.pluginState) return null\n\n const from = this.pluginState.queryStartPos -\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter.length : 0)\n\n const to = this.editor._tiptapEditor.state.selection.from\n\n return { from, to }\n }\n\n}\n\nexport class SuggestionMenuProseMirrorPlugin extends EventEmitter<any> {\n public view: SuggestionMenuView\n public readonly plugin: Plugin\n private triggerCharacters: string[] = []\n\n constructor(editor: MEditor) {\n super()\n const triggerCharacters = this.triggerCharacters\n\n this.plugin = new Plugin({\n key: suggestionMenuPluginKey,\n view: () => {\n this.view = new SuggestionMenuView(editor, (triggerCharacter, state) => {\n this.emit(`update ${triggerCharacter}`, state)\n })\n return this.view\n },\n state: {\n init(): SuggestionPluginState {\n return undefined\n },\n apply(transaction, prev, _oldState, newState): SuggestionPluginState {\n const suggestionPluginTransactionMeta: {\n triggerCharacter: string\n deleteTriggerCharacter?: boolean\n ignoreQueryLength?: boolean\n } | null = transaction.getMeta(suggestionMenuPluginKey)\n\n\n if (\n typeof suggestionPluginTransactionMeta === 'object' &&\n suggestionPluginTransactionMeta !== null &&\n prev === undefined\n ) {\n return {\n triggerCharacter: suggestionPluginTransactionMeta.triggerCharacter,\n deleteTriggerCharacter: suggestionPluginTransactionMeta.deleteTriggerCharacter !== false,\n queryStartPos: transaction.selection?.from || newState.selection.from,\n query: '',\n decorationId: `id_${Math.floor(Math.random() * 0xffffffff)}`,\n ignoreQueryLength: suggestionPluginTransactionMeta?.ignoreQueryLength,\n }\n }\n\n\n if (prev === undefined) {\n return prev\n }\n\n\n if (\n newState.selection.from !== newState.selection.to ||\n suggestionPluginTransactionMeta === null ||\n transaction.getMeta('focus') ||\n transaction.getMeta('blur') ||\n transaction.getMeta('pointer') ||\n (prev.triggerCharacter !== undefined && newState.selection.from < prev.queryStartPos!)\n ) {\n\n return undefined\n }\n\n const next = { ...prev }\n\n\n next.query = newState.doc.textBetween(prev.queryStartPos!, newState.selection.from)\n\n return next\n }\n },\n\n props: {\n // 当用户输入一个 trigger 字符,且当前没有 suggestion 激活时:\n // 插件拦截这次输入,自己插入字符,并通过 transaction meta 通知 state 打开 suggestion 菜单;\n // 其余情况下,完全不干预编辑器行为。\n handleTextInput(view, _from, _to, text) {\n\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(view.state)\n\n if (triggerCharacters.includes(text) && suggestionPluginState === undefined) {\n view.dispatch(\n view.state.tr.insertText(text).scrollIntoView().setMeta(suggestionMenuPluginKey, {\n triggerCharacter: text,\n })\n )\n\n return true\n }\n return false\n },\n\n decorations(state) {\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(state)\n\n if (suggestionPluginState === undefined) {\n return null\n }\n\n \n if (!suggestionPluginState.deleteTriggerCharacter) {\n const blockNode = findBlock(state.selection)\n if (blockNode) {\n return DecorationSet.create(state.doc, [\n Decoration.node(blockNode.pos, blockNode.pos + blockNode.node.nodeSize, {\n nodeName: 'span',\n class: 'bn-suggestion-decorator',\n 'data-decoration-id': suggestionPluginState.decorationId,\n }),\n ])\n }\n }\n \n return DecorationSet.create(state.doc, [\n Decoration.inline(\n suggestionPluginState.queryStartPos! - suggestionPluginState.triggerCharacter!.length,\n suggestionPluginState.queryStartPos!,\n {\n nodeName: 'span',\n class: 'bn-suggestion-decorator',\n 'data-decoration-id': suggestionPluginState.decorationId,\n }\n ),\n ])\n },\n }\n })\n }\n\n public onUpdate(triggerCharacter: string, callback: (state: SuggestionMenuState) => void) {\n if (!this.triggerCharacters.includes(triggerCharacter)) {\n this.addTriggerCharacter(triggerCharacter)\n }\n \n return this.on(`update ${triggerCharacter}`, callback)\n }\n\n addTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters.push(triggerCharacter)\n }\n\n \n removeTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters = this.triggerCharacters.filter(c => c !== triggerCharacter)\n }\n\n closeMenu = () => this.view!.closeMenu()\n\n clearQuery = () => this.view!.clearQuery()\n\n insertMention = (item: MentionItem) => this.view!.insertMention(item)\n\n public get shown() {\n return this.view?.state?.show || false\n }\n\n}\n","type StringKeyOf<T> = Extract<keyof T, string>\ntype CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[]\n ? T[EventName]\n : [T[EventName]]\ntype CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (...props: CallbackType<T, EventName>) => any\n\nexport class EventEmitter<T extends Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private callbacks: { [key: string]: Function[] } = {}\n\n public on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>) {\n if (!this.callbacks[event]) {\n this.callbacks[event] = []\n }\n\n this.callbacks[event].push(fn)\n\n return () => this.off(event, fn)\n }\n\n protected emit<EventName extends StringKeyOf<T>>(event: EventName, ...args: CallbackType<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n callbacks.forEach(callback => callback.apply(this, args))\n }\n }\n\n public off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n if (fn) {\n this.callbacks[event] = callbacks.filter(callback => callback !== fn)\n } else {\n delete this.callbacks[event]\n }\n }\n }\n\n protected removeAllListeners(): void {\n this.callbacks = {}\n }\n}\n","import { Node } from '@tiptap/core'\n\nexport const MentionBlock = Node.create({\n name: 'mention',\n inline: true,\n group: 'inline',\n atom: true,\n selectable: false,\n\n addAttributes() {\n return {\n id: { default: null },\n label: { default: null },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'span[data-type=\"mention\"]',\n },\n ]\n },\n\n renderHTML({ node }) {\n return [\n 'span',\n {\n class: 'mention',\n 'data-type': 'mention',\n 'data-id': node.attrs.id,\n 'data-label': node.attrs.label,\n contenteditable: 'false', // 非编辑\n },\n node.attrs.label,\n ]\n },\n\n // 新增:确保mention节点可以正确序列化/反序列化\n renderText({ node }) {\n return ''\n },\n})\n\n\n","import { Selection } from 'prosemirror-state'\nimport MEditor from '../editor'\n\nexport function InsertMentionBlock(\n editor: MEditor,\n item: { id: string; label: string }\n) {\n\n editor._tiptapEditor.chain().insertContent({\n type: 'mention',\n attrs: {\n id: item.id,\n label: item.label,\n }\n }).run() \n\n}\n\n","import { Plugin, PluginKey } from 'prosemirror-state'\nimport MEditor from '../../editor'\nimport { MentionItem } from '../SuggestionMenu/types'\n\nexport class MentionDeletePlugin {\n public readonly plugin: Plugin\n\n constructor(editor: MEditor, onMentionDelete?: (item: MentionItem) => void) {\n this.plugin = new Plugin({\n key: new PluginKey('mention-delete'),\n\n appendTransaction(transactions, oldState, newState) {\n if (!transactions.some(tr => tr.docChanged)) {\n return null\n }\n\n const oldMentions = new Map<string, any>()\n const newMentionIds = new Set<string>()\n\n oldState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n oldMentions.set(node.attrs.id, node.attrs)\n }\n })\n\n newState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n newMentionIds.add(node.attrs.id)\n }\n })\n\n for (const [id, attrs] of oldMentions.entries()) {\n if (!newMentionIds.has(id)) {\n onMentionDelete?.({\n id: attrs.id,\n label: attrs.label,\n })\n }\n }\n },\n })\n }\n} \n"],"mappings":"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","names":["index_exports","__export","MEditor","index_default","__toCommonJS","import_core","import_extension_document","import_extension_paragraph","import_extension_text","baseExtensions","Document","Paragraph","Text","import_extension_history","import_extension_placeholder","import_core","import_prosemirror_state","FileInputExtension","handleFile","file","_a","_b","_","event","items","item","files","import_core","import_prosemirror_state","import_prosemirror_view","EventEmitter","__publicField","event","fn","args","callbacks","callback","suggestionMenuPluginKey","findBlock","node","SuggestionMenuView","editor","emitUpdate","__publicField","item","menuName","_a","view","prevState","prev","next","started","stopped","decorationNode","from","to","SuggestionMenuProseMirrorPlugin","EventEmitter","triggerCharacter","c","triggerCharacters","state","transaction","_oldState","newState","suggestionPluginTransactionMeta","_from","_to","text","suggestionPluginState","blockNode","callback","_b","import_core","MentionBlock","node","InsertMentionBlock","editor","item","import_prosemirror_state","MentionDeletePlugin","editor","onMentionDelete","__publicField","transactions","oldState","newState","tr","oldMentions","newMentionIds","node","id","attrs","MEditor","options","__publicField","SuggestionMenuProseMirrorPlugin","MentionDeletePlugin","MEditorUIExtension","baseExtensions","History","MentionBlock","Placeholder","FileInputExtension","editor","tr","item","InsertMentionBlock","mentions","node","pos","_a","_b","index_default","MEditor"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/editor.ts","../src/schema/base.ts","../src/extensions/FileInput/FileInput.ts","../src/extensions/SuggestionMenu/SuggestionPlugin.ts","../src/utils/EventEmitter.ts","../src/blocks/MentionBlock.ts","../src/api/InsertMentionBlock.ts","../src/extensions/MentionDeletePlugin/MentionDeletePlugin.ts","../src/extensions/ShiftEnterPlugin/ShiftEnterPlugin.ts"],"sourcesContent":["import MEditor from \"./editor\";\n\nexport * from \"./extensions/SuggestionMenu/types\"\nexport * from \"./extensions/FileInput/types\"\n\nexport { MEditor }\nexport default MEditor","import { Editor, Extension } from '@tiptap/core'\nimport { baseExtensions } from './schema/base'\nimport History from '@tiptap/extension-history'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { FileInputExtension } from './extensions/FileInput/FileInput'\nimport { Transaction } from 'prosemirror-state'\nimport { SuggestionMenuProseMirrorPlugin } from './extensions/SuggestionMenu/SuggestionPlugin'\nimport { MentionBlock } from './blocks/MentionBlock'\nimport { type MentionItem } from './extensions/SuggestionMenu/types'\nimport { InsertMentionBlock } from './api/InsertMentionBlock'\nimport { MentionDeletePlugin } from './extensions/MentionDeletePlugin/MentionDeletePlugin'\nimport { EnterMode } from './extensions/ShiftEnterPlugin/ShiftEnterPlugin'\nimport { ShiftEnterPlugin } from './extensions/ShiftEnterPlugin/ShiftEnterPlugin'\n\nexport interface MentionEditorOptions {\n element: HTMLElement\n onChange: (text: string) => void\n placeholder?: string\n onFileInput?: (file: File) => void\n content?: string\n onMentionDelete?: (item: MentionItem) => void\n onEnter?: () => void\n lineBreak?: EnterMode\n}\n\n\nexport default class MEditor {\n options: MentionEditorOptions\n _tiptapEditor: Editor\n public readonly suggestionMenus: SuggestionMenuProseMirrorPlugin\n public readonly mentionDeletePlugin: MentionDeletePlugin\n public readonly shiftEnterPlugin: ShiftEnterPlugin\n\n constructor(options: MentionEditorOptions) {\n this.options = options\n this.suggestionMenus = new SuggestionMenuProseMirrorPlugin(this)\n this.mentionDeletePlugin = new MentionDeletePlugin(this, options.onMentionDelete)\n this.shiftEnterPlugin = new ShiftEnterPlugin(this, options.onEnter)\n\n const MEditorUIExtension = Extension.create({\n name: 'MEditorUIExtension',\n addProseMirrorPlugins: () => {\n const plugins = [\n this.suggestionMenus.plugin,\n this.mentionDeletePlugin.plugin,\n this.shiftEnterPlugin.plugin,\n ]\n\n return plugins\n },\n })\n\n this._tiptapEditor = new Editor({\n element: options.element,\n content: options.content || '',\n extensions: [\n ...baseExtensions,\n History.configure({\n depth: 100,\n newGroupDelay: 500,\n }),\n MentionBlock,\n Placeholder.configure({\n placeholder: options.placeholder || '请输入...',\n emptyEditorClass: 'is-editor-empty'\n }),\n FileInputExtension.configure({\n onFileInput: options.onFileInput,\n }),\n MEditorUIExtension,\n ],\n onUpdate: ({ editor }) => {\n options.onChange(editor.getText())\n }\n })\n }\n\n\n dispatch(tr: Transaction) {\n this._tiptapEditor.view.dispatch(tr)\n }\n\n public inserMentionBlock(item: MentionItem) {\n InsertMentionBlock(this, item)\n // this._tiptapEditor\n // .chain()\n // .focus()\n // .insertContent({\n // type: 'mention',\n // attrs: item\n // })\n // .insertContent(' ')\n // .run()\n }\n\n public get isEditable(): boolean {\n return this._tiptapEditor.isEditable === undefined ? true : this._tiptapEditor.isEditable\n }\n\n public get domElement() {\n return this._tiptapEditor.view.dom as HTMLDivElement\n }\n\n public clear() {\n this._tiptapEditor.commands.clearContent(true)\n this._tiptapEditor.commands.focus()\n }\n\n public getAllMentionBlocks(): Array<MentionItem> {\n const mentions: Array<MentionItem> = []\n\n const doc = this._tiptapEditor.state.doc\n\n doc.descendants((node, pos) => {\n if (node.type.name === 'mention') {\n mentions.push({\n id: node.attrs.id ?? null,\n label: node.attrs.label ?? null,\n })\n }\n })\n\n return mentions\n }\n}\n","import Document from '@tiptap/extension-document'\nimport Paragraph from '@tiptap/extension-paragraph'\nimport Text from '@tiptap/extension-text'\nimport HardBreak from '@tiptap/extension-hard-break'\n\nexport const baseExtensions = [\n Document,\n Paragraph,\n Text,\n HardBreak,\n]\n","import { Extension } from '@tiptap/core'\nimport { Plugin } from 'prosemirror-state'\nimport { FileInputOptions } from './types'\n\nexport const FileInputExtension = Extension.create<FileInputOptions>({\n name: 'imageInput',\n\n addOptions() {\n return {\n onFileInput: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n const handleFile = async (file: File) => {\n this.options.onFileInput?.(file)\n }\n\n return [\n new Plugin({\n props: {\n handlePaste: (_, event) => {\n const items = event.clipboardData?.items\n if (!items) return false\n\n for (const item of items) {\n if (item.kind !== 'file') continue\n const file = item.getAsFile()\n if (!file) continue\n\n handleFile(file)\n return true\n }\n\n return false\n },\n\n handleDrop: (_, event) => {\n const files = event.dataTransfer?.files\n if (!files || files.length === 0) return false\n\n handleFile(files[0])\n return true\n },\n },\n }),\n ]\n },\n})\n","import { findParentNode } from '@tiptap/core'\r\nimport { EditorState, Plugin, PluginKey } from 'prosemirror-state'\r\nimport { Decoration, DecorationSet, EditorView } from 'prosemirror-view'\r\nimport MEditor from '../../editor'\r\nimport { EventEmitter } from '../../utils/EventEmitter'\r\nimport { SuggestionMenuState, MentionItem } from './types'\r\n\r\ntype SuggestionPluginState =\r\n | {\r\n triggerCharacter: string\r\n deleteTriggerCharacter: boolean\r\n queryStartPos: number\r\n query: string\r\n decorationId: string\r\n ignoreQueryLength?: boolean\r\n }\r\n | undefined\r\n\r\nexport const suggestionMenuPluginKey = new PluginKey('SuggestionMenuPlugin')\r\nconst findBlock = findParentNode(node => node.type.name === 'blockContainer')\r\n\r\nclass SuggestionMenuView {\r\n pluginState: SuggestionPluginState\r\n public state?: SuggestionMenuState\r\n public emitUpdate: (triggerCharacter: string) => void\r\n private rootEl?: Document | ShadowRoot\r\n\r\n constructor(\r\n private readonly editor: MEditor,\r\n emitUpdate: (menuName: string, state: SuggestionMenuState) => void\r\n ) {\r\n this.pluginState = undefined\r\n\r\n this.emitUpdate = (menuName: string) => {\r\n if (!this.state) {\r\n throw new Error('Attempting to update uninitialized suggestions menu')\r\n }\r\n emitUpdate(menuName, {\r\n ...this.state,\r\n ignoreQueryLength: this.pluginState?.ignoreQueryLength,\r\n })\r\n }\r\n setTimeout(() => {\r\n this.rootEl = this.editor._tiptapEditor.view.root\r\n })\r\n\r\n }\r\n\r\n update(view: EditorView, prevState: EditorState) {\r\n\r\n const prev: SuggestionPluginState = suggestionMenuPluginKey.getState(prevState)\r\n const next: SuggestionPluginState = suggestionMenuPluginKey.getState(view.state)\r\n\r\n \r\n const started = prev === undefined && next !== undefined\r\n const stopped = prev !== undefined && next === undefined\r\n const changed = prev !== undefined && next !== undefined\r\n\r\n \r\n if (!started && !changed && !stopped) {\r\n return\r\n }\r\n\r\n this.pluginState = stopped ? prev : next\r\n\r\n if (stopped || !this.editor.isEditable) {\r\n\r\n this.state!.show = false\r\n this.emitUpdate(this.pluginState!.triggerCharacter)\r\n\r\n return\r\n }\r\n\r\n const decorationNode = this.rootEl?.querySelector(`[data-decoration-id=\"${this.pluginState!.decorationId}\"]`)\r\n\r\n if (this.editor.isEditable && decorationNode) {\r\n\r\n this.state = {\r\n show: true,\r\n referencePos: decorationNode.getBoundingClientRect(),\r\n query: this.pluginState!.query,\r\n }\r\n\r\n this.emitUpdate(this.pluginState!.triggerCharacter!)\r\n }\r\n }\r\n\r\n destroy() {\r\n\r\n }\r\n\r\n closeMenu = () => {\r\n this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(suggestionMenuPluginKey, null))\r\n }\r\n\r\n clearQuery = () => {\r\n if (this.pluginState === undefined) {\r\n return\r\n }\r\n\r\n this.editor._tiptapEditor\r\n .chain()\r\n .focus()\r\n .deleteRange({\r\n from:\r\n this.pluginState.queryStartPos! -\r\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter!.length : 0),\r\n to: this.editor._tiptapEditor.state.selection.from,\r\n })\r\n .run()\r\n }\r\n\r\n insertMention = (item: MentionItem) => {\r\n this.editor._tiptapEditor\r\n .chain()\r\n .focus()\r\n .insertContent({\r\n type: 'mention',\r\n attrs: item\r\n })\r\n .insertContent(' ')\r\n .run()\r\n }\r\n\r\n getReplaceRange() {\r\n if (!this.pluginState) return null\r\n\r\n const from = this.pluginState.queryStartPos -\r\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter.length : 0)\r\n\r\n const to = this.editor._tiptapEditor.state.selection.from\r\n\r\n return { from, to }\r\n }\r\n\r\n}\r\n\r\nexport class SuggestionMenuProseMirrorPlugin extends EventEmitter<any> {\r\n public view: SuggestionMenuView\r\n public readonly plugin: Plugin\r\n private triggerCharacters: string[] = []\r\n\r\n constructor(editor: MEditor) {\r\n super()\r\n const triggerCharacters = this.triggerCharacters\r\n\r\n this.plugin = new Plugin({\r\n key: suggestionMenuPluginKey,\r\n view: () => {\r\n this.view = new SuggestionMenuView(editor, (triggerCharacter, state) => {\r\n this.emit(`update ${triggerCharacter}`, state)\r\n })\r\n return this.view\r\n },\r\n state: {\r\n init(): SuggestionPluginState {\r\n return undefined\r\n },\r\n apply(transaction, prev, _oldState, newState): SuggestionPluginState {\r\n const suggestionPluginTransactionMeta: {\r\n triggerCharacter: string\r\n deleteTriggerCharacter?: boolean\r\n ignoreQueryLength?: boolean\r\n } | null = transaction.getMeta(suggestionMenuPluginKey)\r\n\r\n\r\n if (\r\n typeof suggestionPluginTransactionMeta === 'object' &&\r\n suggestionPluginTransactionMeta !== null &&\r\n prev === undefined\r\n ) {\r\n return {\r\n triggerCharacter: suggestionPluginTransactionMeta.triggerCharacter,\r\n deleteTriggerCharacter: suggestionPluginTransactionMeta.deleteTriggerCharacter !== false,\r\n queryStartPos: transaction.selection?.from || newState.selection.from,\r\n query: '',\r\n decorationId: `id_${Math.floor(Math.random() * 0xffffffff)}`,\r\n ignoreQueryLength: suggestionPluginTransactionMeta?.ignoreQueryLength,\r\n }\r\n }\r\n\r\n\r\n if (prev === undefined) {\r\n return prev\r\n }\r\n\r\n\r\n if (\r\n newState.selection.from !== newState.selection.to ||\r\n suggestionPluginTransactionMeta === null ||\r\n transaction.getMeta('focus') ||\r\n transaction.getMeta('blur') ||\r\n transaction.getMeta('pointer') ||\r\n (prev.triggerCharacter !== undefined && newState.selection.from < prev.queryStartPos!)\r\n ) {\r\n\r\n return undefined\r\n }\r\n\r\n const next = { ...prev }\r\n\r\n\r\n next.query = newState.doc.textBetween(prev.queryStartPos!, newState.selection.from)\r\n\r\n return next\r\n }\r\n },\r\n\r\n props: {\r\n // 当用户输入一个 trigger 字符,且当前没有 suggestion 激活时:\r\n // 插件拦截这次输入,自己插入字符,并通过 transaction meta 通知 state 打开 suggestion 菜单;\r\n // 其余情况下,完全不干预编辑器行为。\r\n handleTextInput(view, _from, _to, text) {\r\n\r\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(view.state)\r\n\r\n if (triggerCharacters.includes(text) && suggestionPluginState === undefined) {\r\n view.dispatch(\r\n view.state.tr.insertText(text).scrollIntoView().setMeta(suggestionMenuPluginKey, {\r\n triggerCharacter: text,\r\n })\r\n )\r\n\r\n return true\r\n }\r\n return false\r\n },\r\n\r\n decorations(state) {\r\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(state)\r\n\r\n if (suggestionPluginState === undefined) {\r\n return null\r\n }\r\n\r\n \r\n if (!suggestionPluginState.deleteTriggerCharacter) {\r\n const blockNode = findBlock(state.selection)\r\n if (blockNode) {\r\n return DecorationSet.create(state.doc, [\r\n Decoration.node(blockNode.pos, blockNode.pos + blockNode.node.nodeSize, {\r\n nodeName: 'span',\r\n class: 'bn-suggestion-decorator',\r\n 'data-decoration-id': suggestionPluginState.decorationId,\r\n }),\r\n ])\r\n }\r\n }\r\n \r\n return DecorationSet.create(state.doc, [\r\n Decoration.inline(\r\n suggestionPluginState.queryStartPos! - suggestionPluginState.triggerCharacter!.length,\r\n suggestionPluginState.queryStartPos!,\r\n {\r\n nodeName: 'span',\r\n class: 'bn-suggestion-decorator',\r\n 'data-decoration-id': suggestionPluginState.decorationId,\r\n }\r\n ),\r\n ])\r\n },\r\n }\r\n })\r\n }\r\n\r\n public onUpdate(triggerCharacter: string, callback: (state: SuggestionMenuState) => void) {\r\n if (!this.triggerCharacters.includes(triggerCharacter)) {\r\n this.addTriggerCharacter(triggerCharacter)\r\n }\r\n \r\n return this.on(`update ${triggerCharacter}`, callback)\r\n }\r\n\r\n addTriggerCharacter = (triggerCharacter: string) => {\r\n this.triggerCharacters.push(triggerCharacter)\r\n }\r\n\r\n \r\n removeTriggerCharacter = (triggerCharacter: string) => {\r\n this.triggerCharacters = this.triggerCharacters.filter(c => c !== triggerCharacter)\r\n }\r\n\r\n closeMenu = () => this.view!.closeMenu()\r\n\r\n clearQuery = () => this.view!.clearQuery()\r\n\r\n insertMention = (item: MentionItem) => this.view!.insertMention(item)\r\n\r\n public get shown() {\r\n return this.view?.state?.show || false\r\n }\r\n\r\n}\r\n","type StringKeyOf<T> = Extract<keyof T, string>\ntype CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[]\n ? T[EventName]\n : [T[EventName]]\ntype CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (...props: CallbackType<T, EventName>) => any\n\nexport class EventEmitter<T extends Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private callbacks: { [key: string]: Function[] } = {}\n\n public on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>) {\n if (!this.callbacks[event]) {\n this.callbacks[event] = []\n }\n\n this.callbacks[event].push(fn)\n\n return () => this.off(event, fn)\n }\n\n protected emit<EventName extends StringKeyOf<T>>(event: EventName, ...args: CallbackType<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n callbacks.forEach(callback => callback.apply(this, args))\n }\n }\n\n public off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n if (fn) {\n this.callbacks[event] = callbacks.filter(callback => callback !== fn)\n } else {\n delete this.callbacks[event]\n }\n }\n }\n\n protected removeAllListeners(): void {\n this.callbacks = {}\n }\n}\n","import { Node } from '@tiptap/core'\n\nexport const MentionBlock = Node.create({\n name: 'mention',\n inline: true,\n group: 'inline',\n atom: true,\n selectable: false,\n\n addAttributes() {\n return {\n id: { default: null },\n label: { default: null },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'span[data-type=\"mention\"]',\n },\n ]\n },\n\n renderHTML({ node }) {\n return [\n 'span',\n {\n class: 'mention',\n 'data-type': 'mention',\n 'data-id': node.attrs.id,\n 'data-label': node.attrs.label,\n contenteditable: 'false', // 非编辑\n },\n node.attrs.label,\n ]\n },\n\n // 新增:确保mention节点可以正确序列化/反序列化\n renderText({ node }) {\n return ''\n },\n})\n\n\n","import { Selection } from 'prosemirror-state'\nimport MEditor from '../editor'\n\nexport function InsertMentionBlock(\n editor: MEditor,\n item: { id: string; label: string }\n) {\n\n editor._tiptapEditor.chain().insertContent({\n type: 'mention',\n attrs: {\n id: item.id,\n label: item.label,\n }\n }).run() \n\n}\n\n","import { Plugin, PluginKey } from 'prosemirror-state'\nimport MEditor from '../../editor'\nimport { MentionItem } from '../SuggestionMenu/types'\n\nexport class MentionDeletePlugin {\n public readonly plugin: Plugin\n\n constructor(editor: MEditor, onMentionDelete?: (item: MentionItem) => void) {\n this.plugin = new Plugin({\n key: new PluginKey('mention-delete'),\n\n appendTransaction(transactions, oldState, newState) {\n if (!transactions.some(tr => tr.docChanged)) {\n return null\n }\n\n const oldMentions = new Map<string, any>()\n const newMentionIds = new Set<string>()\n\n oldState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n oldMentions.set(node.attrs.id, node.attrs)\n }\n })\n\n newState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n newMentionIds.add(node.attrs.id)\n }\n })\n\n for (const [id, attrs] of oldMentions.entries()) {\n if (!newMentionIds.has(id)) {\n onMentionDelete?.({\n id: attrs.id,\n label: attrs.label,\n })\n }\n }\n },\n })\n }\n} \n","import { Plugin, PluginKey } from 'prosemirror-state'\nimport MEditor from '../../editor'\n\nexport const ShiftEnterPluginKey = new PluginKey('ShiftEnterPluginKey')\nexport type EnterMode = 'enter' | 'shift+enter'\n\nexport class ShiftEnterPlugin {\n public readonly plugin: Plugin\n\n constructor(editor: MEditor, onEnter?: () => void) {\n this.plugin = new Plugin({\n key: ShiftEnterPluginKey,\n\n props: {\n handleKeyDown(view, event) {\n\n if (event.key !== 'Enter') {\n return false\n }\n\n const enterMode: EnterMode = editor.options.lineBreak ?? 'enter'\n const isShift = event.shiftKey\n\n // enter模式 enter换行 shift+enter调用onEnter\n // shift+enter模式 shift+enter换行 enter调用onEnter\n const shouldCallOnEnter =\n (enterMode === 'enter' && isShift) ||\n (enterMode === 'shift+enter' && !isShift)\n\n const shouldInsertBreak = !shouldCallOnEnter\n\n // ---------- 调用 onEnter ----------\n if (shouldCallOnEnter) {\n // suggestion 打开时,让 suggestion 处理\n if (editor.suggestionMenus?.shown) {\n return false\n }\n\n if (onEnter) {\n event.preventDefault()\n onEnter()\n return true\n }\n\n return false\n }\n\n // ---------- 默认换行 ----------\n if (shouldInsertBreak) {\n event.preventDefault()\n\n const { state, dispatch } = view\n const { hard_break } = state.schema.nodes\n\n if (!hard_break) {\n return false\n }\n\n dispatch(\n state.tr\n .replaceSelectionWith(hard_break.create())\n .scrollIntoView(),\n )\n\n return true\n }\n\n return false\n },\n },\n\n })\n }\n}"],"mappings":"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","names":["index_exports","__export","MEditor","index_default","__toCommonJS","import_core","import_extension_document","import_extension_paragraph","import_extension_text","import_extension_hard_break","baseExtensions","Document","Paragraph","Text","HardBreak","import_extension_history","import_extension_placeholder","import_core","import_prosemirror_state","FileInputExtension","handleFile","file","_a","_b","_","event","items","item","files","import_core","import_prosemirror_state","import_prosemirror_view","EventEmitter","__publicField","event","fn","args","callbacks","callback","suggestionMenuPluginKey","findBlock","node","SuggestionMenuView","editor","emitUpdate","__publicField","item","menuName","_a","view","prevState","prev","next","started","stopped","decorationNode","from","to","SuggestionMenuProseMirrorPlugin","EventEmitter","triggerCharacter","c","triggerCharacters","state","transaction","_oldState","newState","suggestionPluginTransactionMeta","_from","_to","text","suggestionPluginState","blockNode","callback","_b","import_core","MentionBlock","node","InsertMentionBlock","editor","item","import_prosemirror_state","MentionDeletePlugin","editor","onMentionDelete","__publicField","transactions","oldState","newState","tr","oldMentions","newMentionIds","node","id","attrs","import_prosemirror_state","ShiftEnterPluginKey","ShiftEnterPlugin","editor","onEnter","__publicField","view","event","_a","_b","enterMode","isShift","shouldCallOnEnter","shouldInsertBreak","state","dispatch","hard_break","MEditor","options","__publicField","SuggestionMenuProseMirrorPlugin","MentionDeletePlugin","ShiftEnterPlugin","MEditorUIExtension","baseExtensions","History","MentionBlock","Placeholder","FileInputExtension","editor","tr","item","InsertMentionBlock","mentions","node","pos","_a","_b","index_default","MEditor"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var T=Object.defineProperty;var x=(s,t,e)=>t in s?T(s,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[t]=e;var a=(s,t,e)=>x(s,typeof t!="symbol"?t+"":t,e);import{Editor as K,Extension as Q}from"@tiptap/core";import I from"@tiptap/extension-document";import k from"@tiptap/extension-paragraph";import v from"@tiptap/extension-text";var E=[I,k,v];import R from"@tiptap/extension-history";import U from"@tiptap/extension-placeholder";import{Extension as w}from"@tiptap/core";import{Plugin as N}from"prosemirror-state";var b=w.create({name:"imageInput",addOptions(){return{onFileInput:void 0}},addProseMirrorPlugins(){let s=async t=>{var e,i;(i=(e=this.options).onFileInput)==null||i.call(e,t)};return[new N({props:{handlePaste:(t,e)=>{var n;let i=(n=e.clipboardData)==null?void 0:n.items;if(!i)return!1;for(let r of i){if(r.kind!=="file")continue;let l=r.getAsFile();if(l)return s(l),!0}return!1},handleDrop:(t,e)=>{var n;let i=(n=e.dataTransfer)==null?void 0:n.files;return!i||i.length===0?!1:(s(i[0]),!0)}}})]}});import{findParentNode as _}from"@tiptap/core";import{Plugin as F,PluginKey as q}from"prosemirror-state";import{Decoration as S,DecorationSet as M}from"prosemirror-view";var p=class{constructor(){a(this,"callbacks",{})}on(t,e){return this.callbacks[t]||(this.callbacks[t]=[]),this.callbacks[t].push(e),()=>this.off(t,e)}emit(t,...e){let i=this.callbacks[t];i&&i.forEach(n=>n.apply(this,e))}off(t,e){let i=this.callbacks[t];i&&(e?this.callbacks[t]=i.filter(n=>n!==e):delete this.callbacks[t])}removeAllListeners(){this.callbacks={}}};var c=new q("SuggestionMenuPlugin"),L=_(s=>s.type.name==="blockContainer"),f=class{constructor(t,e){this.editor=t;a(this,"pluginState");a(this,"state");a(this,"emitUpdate");a(this,"rootEl");a(this,"closeMenu",()=>{this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(c,null))});a(this,"clearQuery",()=>{this.pluginState!==void 0&&this.editor._tiptapEditor.chain().focus().deleteRange({from:this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),to:this.editor._tiptapEditor.state.selection.from}).run()});a(this,"insertMention",t=>{this.editor._tiptapEditor.chain().focus().insertContent({type:"mention",attrs:t}).insertContent(" ").run()});this.pluginState=void 0,this.emitUpdate=i=>{var n;if(!this.state)throw new Error("Attempting to update uninitialized suggestions menu");e(i,{...this.state,ignoreQueryLength:(n=this.pluginState)==null?void 0:n.ignoreQueryLength})},setTimeout(()=>{this.rootEl=this.editor._tiptapEditor.view.root})}update(t,e){var u;let i=c.getState(e),n=c.getState(t.state),r=i===void 0&&n!==void 0,l=i!==void 0&&n===void 0;if(!r&&!(i!==void 0&&n!==void 0)&&!l)return;if(this.pluginState=l?i:n,l||!this.editor.isEditable){this.state.show=!1,this.emitUpdate(this.pluginState.triggerCharacter);return}let o=(u=this.rootEl)==null?void 0:u.querySelector(`[data-decoration-id="${this.pluginState.decorationId}"]`);this.editor.isEditable&&o&&(this.state={show:!0,referencePos:o.getBoundingClientRect(),query:this.pluginState.query},this.emitUpdate(this.pluginState.triggerCharacter))}destroy(){}getReplaceRange(){if(!this.pluginState)return null;let t=this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),e=this.editor._tiptapEditor.state.selection.from;return{from:t,to:e}}},m=class extends p{constructor(e){super();a(this,"view");a(this,"plugin");a(this,"triggerCharacters",[]);a(this,"addTriggerCharacter",e=>{this.triggerCharacters.push(e)});a(this,"removeTriggerCharacter",e=>{this.triggerCharacters=this.triggerCharacters.filter(i=>i!==e)});a(this,"closeMenu",()=>this.view.closeMenu());a(this,"clearQuery",()=>this.view.clearQuery());a(this,"insertMention",e=>this.view.insertMention(e));let i=this.triggerCharacters;this.plugin=new F({key:c,view:()=>(this.view=new f(e,(n,r)=>{this.emit(`update ${n}`,r)}),this.view),state:{init(){},apply(n,r,l,d){var y;let o=n.getMeta(c);if(typeof o=="object"&&o!==null&&r===void 0)return{triggerCharacter:o.triggerCharacter,deleteTriggerCharacter:o.deleteTriggerCharacter!==!1,queryStartPos:((y=n.selection)==null?void 0:y.from)||d.selection.from,query:"",decorationId:`id_${Math.floor(Math.random()*4294967295)}`,ignoreQueryLength:o==null?void 0:o.ignoreQueryLength};if(r===void 0)return r;if(d.selection.from!==d.selection.to||o===null||n.getMeta("focus")||n.getMeta("blur")||n.getMeta("pointer")||r.triggerCharacter!==void 0&&d.selection.from<r.queryStartPos)return;let u={...r};return u.query=d.doc.textBetween(r.queryStartPos,d.selection.from),u}},props:{handleTextInput(n,r,l,d){let o=this.getState(n.state);return i.includes(d)&&o===void 0?(n.dispatch(n.state.tr.insertText(d).scrollIntoView().setMeta(c,{triggerCharacter:d})),!0):!1},decorations(n){let r=this.getState(n);if(r===void 0)return null;if(!r.deleteTriggerCharacter){let l=L(n.selection);if(l)return M.create(n.doc,[S.node(l.pos,l.pos+l.node.nodeSize,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":r.decorationId})])}return M.create(n.doc,[S.inline(r.queryStartPos-r.triggerCharacter.length,r.queryStartPos,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":r.decorationId})])}}})}onUpdate(e,i){return this.triggerCharacters.includes(e)||this.addTriggerCharacter(e),this.on(`update ${e}`,i)}get shown(){var e,i;return((i=(e=this.view)==null?void 0:e.state)==null?void 0:i.show)||!1}};import{Node as O}from"@tiptap/core";var C=O.create({name:"mention",inline:!0,group:"inline",atom:!0,selectable:!1,addAttributes(){return{id:{default:null},label:{default:null}}},parseHTML(){return[{tag:'span[data-type="mention"]'}]},renderHTML({node:s}){return["span",{class:"mention","data-type":"mention","data-id":s.attrs.id,"data-label":s.attrs.label,contenteditable:"false"},s.attrs.label]},renderText({node:s}){return""}});function P(s,t){s._tiptapEditor.chain().insertContent({type:"mention",attrs:{id:t.id,label:t.label}}).run()}import{Plugin as D,PluginKey as B}from"prosemirror-state";var h=class{constructor(t,e){a(this,"plugin");this.plugin=new D({key:new B("mention-delete"),appendTransaction(i,n,r){if(!i.some(o=>o.docChanged))return null;let l=new Map,d=new Set;n.doc.descendants(o=>{o.type.name==="mention"&&o.attrs.id&&l.set(o.attrs.id,o.attrs)}),r.doc.descendants(o=>{o.type.name==="mention"&&o.attrs.id&&d.add(o.attrs.id)});for(let[o,u]of l.entries())d.has(o)||e==null||e({id:u.id,label:u.label})}})}};var g=class{constructor(t){a(this,"_tiptapEditor");a(this,"suggestionMenus");a(this,"mentionDeletePlugin");this.suggestionMenus=new m(this),this.mentionDeletePlugin=new h(this,t.onMentionDelete);let e=Q.create({name:"MEditorUIExtension",addProseMirrorPlugins:()=>[this.suggestionMenus.plugin,this.mentionDeletePlugin.plugin]});this._tiptapEditor=new K({element:t.element,content:t.content||"",extensions:[...E,R.configure({depth:100,newGroupDelay:500}),C,U.configure({placeholder:t.placeholder||"\u8BF7\u8F93\u5165...",emptyEditorClass:"is-editor-empty"}),b.configure({onFileInput:t.onFileInput}),e],onUpdate:({editor:i})=>{t.onChange(i.getText())}})}dispatch(t){this._tiptapEditor.view.dispatch(t)}inserMentionBlock(t){P(this,t)}get isEditable(){return this._tiptapEditor.isEditable===void 0?!0:this._tiptapEditor.isEditable}get domElement(){return this._tiptapEditor.view.dom}clear(){this._tiptapEditor.commands.clearContent(!0),this._tiptapEditor.commands.focus()}getAllMentionBlocks(){let t=[];return this._tiptapEditor.state.doc.descendants((i,n)=>{var r,l;i.type.name==="mention"&&t.push({id:(r=i.attrs.id)!=null?r:null,label:(l=i.attrs.label)!=null?l:null})}),t}};var Tt=g;export{g as MEditor,Tt as default};
1
+ var I=Object.defineProperty;var v=(a,t,e)=>t in a?I(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var s=(a,t,e)=>v(a,typeof t!="symbol"?t+"":t,e);import{Editor as z,Extension as j}from"@tiptap/core";import _ from"@tiptap/extension-document";import N from"@tiptap/extension-paragraph";import F from"@tiptap/extension-text";import q from"@tiptap/extension-hard-break";var M=[_,N,F,q];import G from"@tiptap/extension-history";import W from"@tiptap/extension-placeholder";import{Extension as K}from"@tiptap/core";import{Plugin as B}from"prosemirror-state";var P=K.create({name:"imageInput",addOptions(){return{onFileInput:void 0}},addProseMirrorPlugins(){let a=async t=>{var e,i;(i=(e=this.options).onFileInput)==null||i.call(e,t)};return[new B({props:{handlePaste:(t,e)=>{var n;let i=(n=e.clipboardData)==null?void 0:n.items;if(!i)return!1;for(let r of i){if(r.kind!=="file")continue;let l=r.getAsFile();if(l)return a(l),!0}return!1},handleDrop:(t,e)=>{var n;let i=(n=e.dataTransfer)==null?void 0:n.files;return!i||i.length===0?!1:(a(i[0]),!0)}}})]}});import{findParentNode as D}from"@tiptap/core";import{Plugin as O,PluginKey as L}from"prosemirror-state";import{Decoration as x,DecorationSet as C}from"prosemirror-view";var f=class{constructor(){s(this,"callbacks",{})}on(t,e){return this.callbacks[t]||(this.callbacks[t]=[]),this.callbacks[t].push(e),()=>this.off(t,e)}emit(t,...e){let i=this.callbacks[t];i&&i.forEach(n=>n.apply(this,e))}off(t,e){let i=this.callbacks[t];i&&(e?this.callbacks[t]=i.filter(n=>n!==e):delete this.callbacks[t])}removeAllListeners(){this.callbacks={}}};var c=new L("SuggestionMenuPlugin"),Q=D(a=>a.type.name==="blockContainer"),y=class{constructor(t,e){this.editor=t;s(this,"pluginState");s(this,"state");s(this,"emitUpdate");s(this,"rootEl");s(this,"closeMenu",()=>{this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(c,null))});s(this,"clearQuery",()=>{this.pluginState!==void 0&&this.editor._tiptapEditor.chain().focus().deleteRange({from:this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),to:this.editor._tiptapEditor.state.selection.from}).run()});s(this,"insertMention",t=>{this.editor._tiptapEditor.chain().focus().insertContent({type:"mention",attrs:t}).insertContent(" ").run()});this.pluginState=void 0,this.emitUpdate=i=>{var n;if(!this.state)throw new Error("Attempting to update uninitialized suggestions menu");e(i,{...this.state,ignoreQueryLength:(n=this.pluginState)==null?void 0:n.ignoreQueryLength})},setTimeout(()=>{this.rootEl=this.editor._tiptapEditor.view.root})}update(t,e){var d;let i=c.getState(e),n=c.getState(t.state),r=i===void 0&&n!==void 0,l=i!==void 0&&n===void 0;if(!r&&!(i!==void 0&&n!==void 0)&&!l)return;if(this.pluginState=l?i:n,l||!this.editor.isEditable){this.state.show=!1,this.emitUpdate(this.pluginState.triggerCharacter);return}let o=(d=this.rootEl)==null?void 0:d.querySelector(`[data-decoration-id="${this.pluginState.decorationId}"]`);this.editor.isEditable&&o&&(this.state={show:!0,referencePos:o.getBoundingClientRect(),query:this.pluginState.query},this.emitUpdate(this.pluginState.triggerCharacter))}destroy(){}getReplaceRange(){if(!this.pluginState)return null;let t=this.pluginState.queryStartPos-(this.pluginState.deleteTriggerCharacter?this.pluginState.triggerCharacter.length:0),e=this.editor._tiptapEditor.state.selection.from;return{from:t,to:e}}},h=class extends f{constructor(e){super();s(this,"view");s(this,"plugin");s(this,"triggerCharacters",[]);s(this,"addTriggerCharacter",e=>{this.triggerCharacters.push(e)});s(this,"removeTriggerCharacter",e=>{this.triggerCharacters=this.triggerCharacters.filter(i=>i!==e)});s(this,"closeMenu",()=>this.view.closeMenu());s(this,"clearQuery",()=>this.view.clearQuery());s(this,"insertMention",e=>this.view.insertMention(e));let i=this.triggerCharacters;this.plugin=new O({key:c,view:()=>(this.view=new y(e,(n,r)=>{this.emit(`update ${n}`,r)}),this.view),state:{init(){},apply(n,r,l,u){var g;let o=n.getMeta(c);if(typeof o=="object"&&o!==null&&r===void 0)return{triggerCharacter:o.triggerCharacter,deleteTriggerCharacter:o.deleteTriggerCharacter!==!1,queryStartPos:((g=n.selection)==null?void 0:g.from)||u.selection.from,query:"",decorationId:`id_${Math.floor(Math.random()*4294967295)}`,ignoreQueryLength:o==null?void 0:o.ignoreQueryLength};if(r===void 0)return r;if(u.selection.from!==u.selection.to||o===null||n.getMeta("focus")||n.getMeta("blur")||n.getMeta("pointer")||r.triggerCharacter!==void 0&&u.selection.from<r.queryStartPos)return;let d={...r};return d.query=u.doc.textBetween(r.queryStartPos,u.selection.from),d}},props:{handleTextInput(n,r,l,u){let o=this.getState(n.state);return i.includes(u)&&o===void 0?(n.dispatch(n.state.tr.insertText(u).scrollIntoView().setMeta(c,{triggerCharacter:u})),!0):!1},decorations(n){let r=this.getState(n);if(r===void 0)return null;if(!r.deleteTriggerCharacter){let l=Q(n.selection);if(l)return C.create(n.doc,[x.node(l.pos,l.pos+l.node.nodeSize,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":r.decorationId})])}return C.create(n.doc,[x.inline(r.queryStartPos-r.triggerCharacter.length,r.queryStartPos,{nodeName:"span",class:"bn-suggestion-decorator","data-decoration-id":r.decorationId})])}}})}onUpdate(e,i){return this.triggerCharacters.includes(e)||this.addTriggerCharacter(e),this.on(`update ${e}`,i)}get shown(){var e,i;return((i=(e=this.view)==null?void 0:e.state)==null?void 0:i.show)||!1}};import{Node as R}from"@tiptap/core";var T=R.create({name:"mention",inline:!0,group:"inline",atom:!0,selectable:!1,addAttributes(){return{id:{default:null},label:{default:null}}},parseHTML(){return[{tag:'span[data-type="mention"]'}]},renderHTML({node:a}){return["span",{class:"mention","data-type":"mention","data-id":a.attrs.id,"data-label":a.attrs.label,contenteditable:"false"},a.attrs.label]},renderText({node:a}){return""}});function k(a,t){a._tiptapEditor.chain().insertContent({type:"mention",attrs:{id:t.id,label:t.label}}).run()}import{Plugin as U,PluginKey as A}from"prosemirror-state";var m=class{constructor(t,e){s(this,"plugin");this.plugin=new U({key:new A("mention-delete"),appendTransaction(i,n,r){if(!i.some(o=>o.docChanged))return null;let l=new Map,u=new Set;n.doc.descendants(o=>{o.type.name==="mention"&&o.attrs.id&&l.set(o.attrs.id,o.attrs)}),r.doc.descendants(o=>{o.type.name==="mention"&&o.attrs.id&&u.add(o.attrs.id)});for(let[o,d]of l.entries())u.has(o)||e==null||e({id:d.id,label:d.label})}})}};import{Plugin as H,PluginKey as V}from"prosemirror-state";var $=new V("ShiftEnterPluginKey"),E=class{constructor(t,e){s(this,"plugin");this.plugin=new H({key:$,props:{handleKeyDown(i,n){var d,g;if(n.key!=="Enter")return!1;let r=(d=t.options.lineBreak)!=null?d:"enter",l=n.shiftKey,u=r==="enter"&&l||r==="shift+enter"&&!l,o=!u;if(u)return(g=t.suggestionMenus)!=null&&g.shown?!1:e?(n.preventDefault(),e(),!0):!1;if(o){n.preventDefault();let{state:S,dispatch:w}=i,{hard_break:b}=S.schema.nodes;return b?(w(S.tr.replaceSelectionWith(b.create()).scrollIntoView()),!0):!1}return!1}}})}};var p=class{constructor(t){s(this,"options");s(this,"_tiptapEditor");s(this,"suggestionMenus");s(this,"mentionDeletePlugin");s(this,"shiftEnterPlugin");this.options=t,this.suggestionMenus=new h(this),this.mentionDeletePlugin=new m(this,t.onMentionDelete),this.shiftEnterPlugin=new E(this,t.onEnter);let e=j.create({name:"MEditorUIExtension",addProseMirrorPlugins:()=>[this.suggestionMenus.plugin,this.mentionDeletePlugin.plugin,this.shiftEnterPlugin.plugin]});this._tiptapEditor=new z({element:t.element,content:t.content||"",extensions:[...M,G.configure({depth:100,newGroupDelay:500}),T,W.configure({placeholder:t.placeholder||"\u8BF7\u8F93\u5165...",emptyEditorClass:"is-editor-empty"}),P.configure({onFileInput:t.onFileInput}),e],onUpdate:({editor:i})=>{t.onChange(i.getText())}})}dispatch(t){this._tiptapEditor.view.dispatch(t)}inserMentionBlock(t){k(this,t)}get isEditable(){return this._tiptapEditor.isEditable===void 0?!0:this._tiptapEditor.isEditable}get domElement(){return this._tiptapEditor.view.dom}clear(){this._tiptapEditor.commands.clearContent(!0),this._tiptapEditor.commands.focus()}getAllMentionBlocks(){let t=[];return this._tiptapEditor.state.doc.descendants((i,n)=>{var r,l;i.type.name==="mention"&&t.push({id:(r=i.attrs.id)!=null?r:null,label:(l=i.attrs.label)!=null?l:null})}),t}};var Ot=p;export{p as MEditor,Ot as default};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/editor.ts","../src/schema/base.ts","../src/extensions/FileInput/FileInput.ts","../src/extensions/SuggestionMenu/SuggestionPlugin.ts","../src/utils/EventEmitter.ts","../src/blocks/MentionBlock.ts","../src/api/InsertMentionBlock.ts","../src/extensions/MentionDeletePlugin/MentionDeletePlugin.ts","../src/index.ts"],"sourcesContent":["import { Editor, Extension } from '@tiptap/core'\nimport { baseExtensions } from './schema/base'\nimport History from '@tiptap/extension-history'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { FileInputExtension } from './extensions/FileInput/FileInput'\nimport { Transaction } from 'prosemirror-state'\nimport { SuggestionMenuProseMirrorPlugin } from './extensions/SuggestionMenu/SuggestionPlugin'\nimport { MentionBlock } from './blocks/MentionBlock'\nimport { type MentionItem } from './extensions/SuggestionMenu/types'\nimport { InsertMentionBlock } from './api/InsertMentionBlock'\nimport { MentionDeletePlugin } from './extensions/MentionDeletePlugin/MentionDeletePlugin'\n\nexport interface MentionEditorOptions {\n element: HTMLElement\n onChange: (text: string) => void\n placeholder?: string\n onFileInput?: (file: File) => void\n content?: string\n onMentionDelete?: (item: MentionItem) => void\n}\n\n\nexport default class MEditor {\n _tiptapEditor: Editor\n public readonly suggestionMenus: SuggestionMenuProseMirrorPlugin\n public readonly mentionDeletePlugin: MentionDeletePlugin\n\n constructor(options: MentionEditorOptions) {\n this.suggestionMenus = new SuggestionMenuProseMirrorPlugin(this)\n this.mentionDeletePlugin = new MentionDeletePlugin(this, options.onMentionDelete)\n\n const MEditorUIExtension = Extension.create({\n name: 'MEditorUIExtension',\n addProseMirrorPlugins: () => {\n return [\n this.suggestionMenus.plugin,\n this.mentionDeletePlugin.plugin,\n ]\n },\n })\n\n this._tiptapEditor = new Editor({\n element: options.element,\n content: options.content || '',\n extensions: [\n ...baseExtensions,\n History.configure({\n depth: 100,\n newGroupDelay: 500,\n }),\n MentionBlock,\n Placeholder.configure({\n placeholder: options.placeholder || '请输入...',\n emptyEditorClass: 'is-editor-empty'\n }),\n FileInputExtension.configure({\n onFileInput: options.onFileInput,\n }),\n MEditorUIExtension,\n ],\n onUpdate: ({ editor }) => {\n options.onChange(editor.getText())\n }\n })\n }\n\n\n dispatch(tr: Transaction) {\n this._tiptapEditor.view.dispatch(tr)\n }\n\n public inserMentionBlock(item: MentionItem) {\n InsertMentionBlock(this, item)\n // this._tiptapEditor\n // .chain()\n // .focus()\n // .insertContent({\n // type: 'mention',\n // attrs: item\n // })\n // .insertContent(' ')\n // .run()\n }\n\n public get isEditable(): boolean {\n return this._tiptapEditor.isEditable === undefined ? true : this._tiptapEditor.isEditable\n }\n\n public get domElement() {\n return this._tiptapEditor.view.dom as HTMLDivElement\n }\n\n public clear() {\n this._tiptapEditor.commands.clearContent(true)\n this._tiptapEditor.commands.focus()\n }\n\n public getAllMentionBlocks(): Array<MentionItem> {\n const mentions: Array<MentionItem> = []\n\n const doc = this._tiptapEditor.state.doc\n\n doc.descendants((node, pos) => {\n if (node.type.name === 'mention') {\n mentions.push({\n id: node.attrs.id ?? null,\n label: node.attrs.label ?? null,\n })\n }\n })\n\n return mentions\n }\n}\n","import Document from '@tiptap/extension-document'\nimport Paragraph from '@tiptap/extension-paragraph'\nimport Text from '@tiptap/extension-text'\n\nexport const baseExtensions = [\n Document,\n Paragraph,\n Text,\n]\n","import { Extension } from '@tiptap/core'\nimport { Plugin } from 'prosemirror-state'\nimport { FileInputOptions } from './types'\n\nexport const FileInputExtension = Extension.create<FileInputOptions>({\n name: 'imageInput',\n\n addOptions() {\n return {\n onFileInput: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n const handleFile = async (file: File) => {\n this.options.onFileInput?.(file)\n }\n\n return [\n new Plugin({\n props: {\n handlePaste: (_, event) => {\n const items = event.clipboardData?.items\n if (!items) return false\n\n for (const item of items) {\n if (item.kind !== 'file') continue\n const file = item.getAsFile()\n if (!file) continue\n\n handleFile(file)\n return true\n }\n\n return false\n },\n\n handleDrop: (_, event) => {\n const files = event.dataTransfer?.files\n if (!files || files.length === 0) return false\n\n handleFile(files[0])\n return true\n },\n },\n }),\n ]\n },\n})\n","import { findParentNode } from '@tiptap/core'\nimport { EditorState, Plugin, PluginKey } from 'prosemirror-state'\nimport { Decoration, DecorationSet, EditorView } from 'prosemirror-view'\nimport MEditor from '../../editor'\nimport { EventEmitter } from '../../utils/EventEmitter'\nimport { SuggestionMenuState, MentionItem } from './types'\n\ntype SuggestionPluginState =\n | {\n triggerCharacter: string\n deleteTriggerCharacter: boolean\n queryStartPos: number\n query: string\n decorationId: string\n ignoreQueryLength?: boolean\n }\n | undefined\n\nexport const suggestionMenuPluginKey = new PluginKey('SuggestionMenuPlugin')\nconst findBlock = findParentNode(node => node.type.name === 'blockContainer')\n\nclass SuggestionMenuView {\n pluginState: SuggestionPluginState\n public state?: SuggestionMenuState\n public emitUpdate: (triggerCharacter: string) => void\n private rootEl?: Document | ShadowRoot\n\n constructor(\n private readonly editor: MEditor,\n emitUpdate: (menuName: string, state: SuggestionMenuState) => void\n ) {\n this.pluginState = undefined\n\n this.emitUpdate = (menuName: string) => {\n if (!this.state) {\n throw new Error('Attempting to update uninitialized suggestions menu')\n }\n emitUpdate(menuName, {\n ...this.state,\n ignoreQueryLength: this.pluginState?.ignoreQueryLength,\n })\n }\n setTimeout(() => {\n this.rootEl = this.editor._tiptapEditor.view.root\n })\n\n }\n\n update(view: EditorView, prevState: EditorState) {\n\n const prev: SuggestionPluginState = suggestionMenuPluginKey.getState(prevState)\n const next: SuggestionPluginState = suggestionMenuPluginKey.getState(view.state)\n\n \n const started = prev === undefined && next !== undefined\n const stopped = prev !== undefined && next === undefined\n const changed = prev !== undefined && next !== undefined\n\n \n if (!started && !changed && !stopped) {\n return\n }\n\n this.pluginState = stopped ? prev : next\n\n if (stopped || !this.editor.isEditable) {\n\n this.state!.show = false\n this.emitUpdate(this.pluginState!.triggerCharacter)\n\n return\n }\n\n const decorationNode = this.rootEl?.querySelector(`[data-decoration-id=\"${this.pluginState!.decorationId}\"]`)\n\n if (this.editor.isEditable && decorationNode) {\n\n this.state = {\n show: true,\n referencePos: decorationNode.getBoundingClientRect(),\n query: this.pluginState!.query,\n }\n\n this.emitUpdate(this.pluginState!.triggerCharacter!)\n }\n }\n\n destroy() {\n\n }\n\n closeMenu = () => {\n this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(suggestionMenuPluginKey, null))\n }\n\n clearQuery = () => {\n if (this.pluginState === undefined) {\n return\n }\n\n this.editor._tiptapEditor\n .chain()\n .focus()\n .deleteRange({\n from:\n this.pluginState.queryStartPos! -\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter!.length : 0),\n to: this.editor._tiptapEditor.state.selection.from,\n })\n .run()\n }\n\n insertMention = (item: MentionItem) => {\n this.editor._tiptapEditor\n .chain()\n .focus()\n .insertContent({\n type: 'mention',\n attrs: item\n })\n .insertContent(' ')\n .run()\n }\n\n getReplaceRange() {\n if (!this.pluginState) return null\n\n const from = this.pluginState.queryStartPos -\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter.length : 0)\n\n const to = this.editor._tiptapEditor.state.selection.from\n\n return { from, to }\n }\n\n}\n\nexport class SuggestionMenuProseMirrorPlugin extends EventEmitter<any> {\n public view: SuggestionMenuView\n public readonly plugin: Plugin\n private triggerCharacters: string[] = []\n\n constructor(editor: MEditor) {\n super()\n const triggerCharacters = this.triggerCharacters\n\n this.plugin = new Plugin({\n key: suggestionMenuPluginKey,\n view: () => {\n this.view = new SuggestionMenuView(editor, (triggerCharacter, state) => {\n this.emit(`update ${triggerCharacter}`, state)\n })\n return this.view\n },\n state: {\n init(): SuggestionPluginState {\n return undefined\n },\n apply(transaction, prev, _oldState, newState): SuggestionPluginState {\n const suggestionPluginTransactionMeta: {\n triggerCharacter: string\n deleteTriggerCharacter?: boolean\n ignoreQueryLength?: boolean\n } | null = transaction.getMeta(suggestionMenuPluginKey)\n\n\n if (\n typeof suggestionPluginTransactionMeta === 'object' &&\n suggestionPluginTransactionMeta !== null &&\n prev === undefined\n ) {\n return {\n triggerCharacter: suggestionPluginTransactionMeta.triggerCharacter,\n deleteTriggerCharacter: suggestionPluginTransactionMeta.deleteTriggerCharacter !== false,\n queryStartPos: transaction.selection?.from || newState.selection.from,\n query: '',\n decorationId: `id_${Math.floor(Math.random() * 0xffffffff)}`,\n ignoreQueryLength: suggestionPluginTransactionMeta?.ignoreQueryLength,\n }\n }\n\n\n if (prev === undefined) {\n return prev\n }\n\n\n if (\n newState.selection.from !== newState.selection.to ||\n suggestionPluginTransactionMeta === null ||\n transaction.getMeta('focus') ||\n transaction.getMeta('blur') ||\n transaction.getMeta('pointer') ||\n (prev.triggerCharacter !== undefined && newState.selection.from < prev.queryStartPos!)\n ) {\n\n return undefined\n }\n\n const next = { ...prev }\n\n\n next.query = newState.doc.textBetween(prev.queryStartPos!, newState.selection.from)\n\n return next\n }\n },\n\n props: {\n // 当用户输入一个 trigger 字符,且当前没有 suggestion 激活时:\n // 插件拦截这次输入,自己插入字符,并通过 transaction meta 通知 state 打开 suggestion 菜单;\n // 其余情况下,完全不干预编辑器行为。\n handleTextInput(view, _from, _to, text) {\n\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(view.state)\n\n if (triggerCharacters.includes(text) && suggestionPluginState === undefined) {\n view.dispatch(\n view.state.tr.insertText(text).scrollIntoView().setMeta(suggestionMenuPluginKey, {\n triggerCharacter: text,\n })\n )\n\n return true\n }\n return false\n },\n\n decorations(state) {\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(state)\n\n if (suggestionPluginState === undefined) {\n return null\n }\n\n \n if (!suggestionPluginState.deleteTriggerCharacter) {\n const blockNode = findBlock(state.selection)\n if (blockNode) {\n return DecorationSet.create(state.doc, [\n Decoration.node(blockNode.pos, blockNode.pos + blockNode.node.nodeSize, {\n nodeName: 'span',\n class: 'bn-suggestion-decorator',\n 'data-decoration-id': suggestionPluginState.decorationId,\n }),\n ])\n }\n }\n \n return DecorationSet.create(state.doc, [\n Decoration.inline(\n suggestionPluginState.queryStartPos! - suggestionPluginState.triggerCharacter!.length,\n suggestionPluginState.queryStartPos!,\n {\n nodeName: 'span',\n class: 'bn-suggestion-decorator',\n 'data-decoration-id': suggestionPluginState.decorationId,\n }\n ),\n ])\n },\n }\n })\n }\n\n public onUpdate(triggerCharacter: string, callback: (state: SuggestionMenuState) => void) {\n if (!this.triggerCharacters.includes(triggerCharacter)) {\n this.addTriggerCharacter(triggerCharacter)\n }\n \n return this.on(`update ${triggerCharacter}`, callback)\n }\n\n addTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters.push(triggerCharacter)\n }\n\n \n removeTriggerCharacter = (triggerCharacter: string) => {\n this.triggerCharacters = this.triggerCharacters.filter(c => c !== triggerCharacter)\n }\n\n closeMenu = () => this.view!.closeMenu()\n\n clearQuery = () => this.view!.clearQuery()\n\n insertMention = (item: MentionItem) => this.view!.insertMention(item)\n\n public get shown() {\n return this.view?.state?.show || false\n }\n\n}\n","type StringKeyOf<T> = Extract<keyof T, string>\ntype CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[]\n ? T[EventName]\n : [T[EventName]]\ntype CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (...props: CallbackType<T, EventName>) => any\n\nexport class EventEmitter<T extends Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private callbacks: { [key: string]: Function[] } = {}\n\n public on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>) {\n if (!this.callbacks[event]) {\n this.callbacks[event] = []\n }\n\n this.callbacks[event].push(fn)\n\n return () => this.off(event, fn)\n }\n\n protected emit<EventName extends StringKeyOf<T>>(event: EventName, ...args: CallbackType<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n callbacks.forEach(callback => callback.apply(this, args))\n }\n }\n\n public off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n if (fn) {\n this.callbacks[event] = callbacks.filter(callback => callback !== fn)\n } else {\n delete this.callbacks[event]\n }\n }\n }\n\n protected removeAllListeners(): void {\n this.callbacks = {}\n }\n}\n","import { Node } from '@tiptap/core'\n\nexport const MentionBlock = Node.create({\n name: 'mention',\n inline: true,\n group: 'inline',\n atom: true,\n selectable: false,\n\n addAttributes() {\n return {\n id: { default: null },\n label: { default: null },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'span[data-type=\"mention\"]',\n },\n ]\n },\n\n renderHTML({ node }) {\n return [\n 'span',\n {\n class: 'mention',\n 'data-type': 'mention',\n 'data-id': node.attrs.id,\n 'data-label': node.attrs.label,\n contenteditable: 'false', // 非编辑\n },\n node.attrs.label,\n ]\n },\n\n // 新增:确保mention节点可以正确序列化/反序列化\n renderText({ node }) {\n return ''\n },\n})\n\n\n","import { Selection } from 'prosemirror-state'\nimport MEditor from '../editor'\n\nexport function InsertMentionBlock(\n editor: MEditor,\n item: { id: string; label: string }\n) {\n\n editor._tiptapEditor.chain().insertContent({\n type: 'mention',\n attrs: {\n id: item.id,\n label: item.label,\n }\n }).run() \n\n}\n\n","import { Plugin, PluginKey } from 'prosemirror-state'\nimport MEditor from '../../editor'\nimport { MentionItem } from '../SuggestionMenu/types'\n\nexport class MentionDeletePlugin {\n public readonly plugin: Plugin\n\n constructor(editor: MEditor, onMentionDelete?: (item: MentionItem) => void) {\n this.plugin = new Plugin({\n key: new PluginKey('mention-delete'),\n\n appendTransaction(transactions, oldState, newState) {\n if (!transactions.some(tr => tr.docChanged)) {\n return null\n }\n\n const oldMentions = new Map<string, any>()\n const newMentionIds = new Set<string>()\n\n oldState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n oldMentions.set(node.attrs.id, node.attrs)\n }\n })\n\n newState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n newMentionIds.add(node.attrs.id)\n }\n })\n\n for (const [id, attrs] of oldMentions.entries()) {\n if (!newMentionIds.has(id)) {\n onMentionDelete?.({\n id: attrs.id,\n label: attrs.label,\n })\n }\n }\n },\n })\n }\n} \n","import MEditor from \"./editor\";\n\nexport * from \"./extensions/SuggestionMenu/types\"\nexport * from \"./extensions/FileInput/types\"\n\nexport { MEditor }\nexport default MEditor"],"mappings":"oKAAA,OAAS,UAAAA,EAAQ,aAAAC,MAAiB,eCAlC,OAAOC,MAAc,6BACrB,OAAOC,MAAe,8BACtB,OAAOC,MAAU,yBAEV,IAAMC,EAAiB,CAC1BH,EACAC,EACAC,CACJ,EDNA,OAAOE,MAAa,4BACpB,OAAOC,MAAiB,gCEHxB,OAAS,aAAAC,MAAiB,eAC1B,OAAS,UAAAC,MAAc,oBAGhB,IAAMC,EAAqBF,EAAU,OAAyB,CACjE,KAAM,aAEN,YAAa,CACT,MAAO,CACH,YAAa,MACjB,CACJ,EAEA,uBAAwB,CACpB,IAAMG,EAAa,MAAOC,GAAe,CAdjD,IAAAC,EAAAC,GAeYA,GAAAD,EAAA,KAAK,SAAQ,cAAb,MAAAC,EAAA,KAAAD,EAA2BD,EAC/B,EAEA,MAAO,CACH,IAAIH,EAAO,CACP,MAAO,CACH,YAAa,CAACM,EAAGC,IAAU,CArB/C,IAAAH,EAsBwB,IAAMI,GAAQJ,EAAAG,EAAM,gBAAN,YAAAH,EAAqB,MACnC,GAAI,CAACI,EAAO,MAAO,GAEnB,QAAWC,KAAQD,EAAO,CACtB,GAAIC,EAAK,OAAS,OAAQ,SAC1B,IAAMN,EAAOM,EAAK,UAAU,EAC5B,GAAKN,EAEL,OAAAD,EAAWC,CAAI,EACR,EACX,CAEA,MAAO,EACX,EAEA,WAAY,CAACG,EAAGC,IAAU,CArC9C,IAAAH,EAsCwB,IAAMM,GAAQN,EAAAG,EAAM,eAAN,YAAAH,EAAoB,MAClC,MAAI,CAACM,GAASA,EAAM,SAAW,EAAU,IAEzCR,EAAWQ,EAAM,CAAC,CAAC,EACZ,GACX,CACJ,CACJ,CAAC,CACL,CACJ,CACJ,CAAC,EChDD,OAAS,kBAAAC,MAAsB,eAC/B,OAAsB,UAAAC,EAAQ,aAAAC,MAAiB,oBAC/C,OAAS,cAAAC,EAAY,iBAAAC,MAAiC,mBCI/C,IAAMC,EAAN,KAAkD,CAAlD,cAEHC,EAAA,KAAQ,YAA2C,CAAC,GAE7C,GAAqCC,EAAkBC,EAAoC,CAC9F,OAAK,KAAK,UAAUD,CAAK,IACrB,KAAK,UAAUA,CAAK,EAAI,CAAC,GAG7B,KAAK,UAAUA,CAAK,EAAE,KAAKC,CAAE,EAEtB,IAAM,KAAK,IAAID,EAAOC,CAAE,CACnC,CAEU,KAAuCD,KAAqBE,EAAkC,CACpG,IAAMC,EAAY,KAAK,UAAUH,CAAK,EAElCG,GACAA,EAAU,QAAQC,GAAYA,EAAS,MAAM,KAAMF,CAAI,CAAC,CAEhE,CAEO,IAAsCF,EAAkBC,EAAqC,CAChG,IAAME,EAAY,KAAK,UAAUH,CAAK,EAElCG,IACIF,EACA,KAAK,UAAUD,CAAK,EAAIG,EAAU,OAAOC,GAAYA,IAAaH,CAAE,EAEpE,OAAO,KAAK,UAAUD,CAAK,EAGvC,CAEU,oBAA2B,CACjC,KAAK,UAAY,CAAC,CACtB,CACJ,EDzBO,IAAMK,EAA0B,IAAIC,EAAU,sBAAsB,EACrEC,EAAYC,EAAeC,GAAQA,EAAK,KAAK,OAAS,gBAAgB,EAEtEC,EAAN,KAAyB,CAMrB,YACqBC,EACjBC,EACF,CAFmB,YAAAD,EANrBE,EAAA,oBACAA,EAAA,KAAO,SACPA,EAAA,KAAO,cACPA,EAAA,KAAQ,UAkERA,EAAA,iBAAY,IAAM,CACd,KAAK,OAAO,SAAS,KAAK,OAAO,cAAc,KAAK,MAAM,GAAG,QAAQR,EAAyB,IAAI,CAAC,CACvG,GAEAQ,EAAA,kBAAa,IAAM,CACX,KAAK,cAAgB,QAIzB,KAAK,OAAO,cACP,MAAM,EACN,MAAM,EACN,YAAY,CACT,KACI,KAAK,YAAY,eAChB,KAAK,YAAY,uBAAyB,KAAK,YAAY,iBAAkB,OAAS,GAC3F,GAAI,KAAK,OAAO,cAAc,MAAM,UAAU,IAClD,CAAC,EACA,IAAI,CACb,GAEAA,EAAA,qBAAiBC,GAAsB,CACnC,KAAK,OAAO,cACP,MAAM,EACN,MAAM,EACN,cAAc,CACX,KAAM,UACN,MAAOA,CACX,CAAC,EACA,cAAc,GAAG,EACjB,IAAI,CACb,GA3FI,KAAK,YAAc,OAEnB,KAAK,WAAcC,GAAqB,CAjChD,IAAAC,EAkCY,GAAI,CAAC,KAAK,MACN,MAAM,IAAI,MAAM,qDAAqD,EAEzEJ,EAAWG,EAAU,CACjB,GAAG,KAAK,MACR,mBAAmBC,EAAA,KAAK,cAAL,YAAAA,EAAkB,iBACzC,CAAC,CACL,EACA,WAAW,IAAM,CACb,KAAK,OAAS,KAAK,OAAO,cAAc,KAAK,IACjD,CAAC,CAEL,CAEA,OAAOC,EAAkBC,EAAwB,CAhDrD,IAAAF,EAkDQ,IAAMG,EAA8Bd,EAAwB,SAASa,CAAS,EACxEE,EAA8Bf,EAAwB,SAASY,EAAK,KAAK,EAGzEI,EAAUF,IAAS,QAAaC,IAAS,OACzCE,EAAUH,IAAS,QAAaC,IAAS,OAI/C,GAAI,CAACC,GAAW,EAHAF,IAAS,QAAaC,IAAS,SAGnB,CAACE,EACzB,OAKJ,GAFA,KAAK,YAAcA,EAAUH,EAAOC,EAEhCE,GAAW,CAAC,KAAK,OAAO,WAAY,CAEpC,KAAK,MAAO,KAAO,GACnB,KAAK,WAAW,KAAK,YAAa,gBAAgB,EAElD,MACJ,CAEA,IAAMC,GAAiBP,EAAA,KAAK,SAAL,YAAAA,EAAa,cAAc,wBAAwB,KAAK,YAAa,YAAY,MAEpG,KAAK,OAAO,YAAcO,IAE1B,KAAK,MAAQ,CACT,KAAM,GACN,aAAcA,EAAe,sBAAsB,EACnD,MAAO,KAAK,YAAa,KAC7B,EAEA,KAAK,WAAW,KAAK,YAAa,gBAAiB,EAE3D,CAEA,SAAU,CAEV,CAmCA,iBAAkB,CACd,GAAI,CAAC,KAAK,YAAa,OAAO,KAE9B,IAAMC,EAAO,KAAK,YAAY,eACzB,KAAK,YAAY,uBAAyB,KAAK,YAAY,iBAAiB,OAAS,GAEpFC,EAAK,KAAK,OAAO,cAAc,MAAM,UAAU,KAErD,MAAO,CAAE,KAAAD,EAAM,GAAAC,CAAG,CACtB,CAEJ,EAEaC,EAAN,cAA8CC,CAAkB,CAKnE,YAAYhB,EAAiB,CACzB,MAAM,EALVE,EAAA,KAAO,QACPA,EAAA,KAAgB,UAChBA,EAAA,KAAQ,oBAA8B,CAAC,GAqIvCA,EAAA,2BAAuBe,GAA6B,CAChD,KAAK,kBAAkB,KAAKA,CAAgB,CAChD,GAGAf,EAAA,8BAA0Be,GAA6B,CACnD,KAAK,kBAAoB,KAAK,kBAAkB,OAAOC,GAAKA,IAAMD,CAAgB,CACtF,GAEAf,EAAA,iBAAY,IAAM,KAAK,KAAM,UAAU,GAEvCA,EAAA,kBAAa,IAAM,KAAK,KAAM,WAAW,GAEzCA,EAAA,qBAAiBC,GAAsB,KAAK,KAAM,cAAcA,CAAI,GA9IhE,IAAMgB,EAAoB,KAAK,kBAE/B,KAAK,OAAS,IAAIC,EAAO,CACrB,IAAK1B,EACL,KAAM,KACF,KAAK,KAAO,IAAIK,EAAmBC,EAAQ,CAACiB,EAAkBI,IAAU,CACpE,KAAK,KAAK,UAAUJ,CAAgB,GAAII,CAAK,CACjD,CAAC,EACM,KAAK,MAEhB,MAAO,CACH,MAA8B,CAE9B,EACA,MAAMC,EAAad,EAAMe,EAAWC,EAAiC,CA9JrF,IAAAnB,EA+JoB,IAAMoB,EAIKH,EAAY,QAAQ5B,CAAuB,EAGtD,GACI,OAAO+B,GAAoC,UAC3CA,IAAoC,MACpCjB,IAAS,OAET,MAAO,CACH,iBAAkBiB,EAAgC,iBAClD,uBAAwBA,EAAgC,yBAA2B,GACnF,gBAAepB,EAAAiB,EAAY,YAAZ,YAAAjB,EAAuB,OAAQmB,EAAS,UAAU,KACjE,MAAO,GACP,aAAc,MAAM,KAAK,MAAM,KAAK,OAAO,EAAI,UAAU,CAAC,GAC1D,kBAAmBC,GAAA,YAAAA,EAAiC,iBACxD,EAIJ,GAAIjB,IAAS,OACT,OAAOA,EAIX,GACIgB,EAAS,UAAU,OAASA,EAAS,UAAU,IAC/CC,IAAoC,MACpCH,EAAY,QAAQ,OAAO,GAC3BA,EAAY,QAAQ,MAAM,GAC1BA,EAAY,QAAQ,SAAS,GAC5Bd,EAAK,mBAAqB,QAAagB,EAAS,UAAU,KAAOhB,EAAK,cAGvE,OAGJ,IAAMC,EAAO,CAAE,GAAGD,CAAK,EAGvB,OAAAC,EAAK,MAAQe,EAAS,IAAI,YAAYhB,EAAK,cAAgBgB,EAAS,UAAU,IAAI,EAE3Ef,CACX,CACJ,EAEA,MAAO,CAIH,gBAAgBH,EAAMoB,EAAOC,EAAKC,EAAM,CAEpC,IAAMC,EAAgD,KAAgB,SAASvB,EAAK,KAAK,EAEzF,OAAIa,EAAkB,SAASS,CAAI,GAAKC,IAA0B,QAC9DvB,EAAK,SACDA,EAAK,MAAM,GAAG,WAAWsB,CAAI,EAAE,eAAe,EAAE,QAAQlC,EAAyB,CAC7E,iBAAkBkC,CACtB,CAAC,CACL,EAEO,IAEJ,EACX,EAEA,YAAYP,EAAO,CACf,IAAMQ,EAAgD,KAAgB,SAASR,CAAK,EAEpF,GAAIQ,IAA0B,OAC1B,OAAO,KAIX,GAAI,CAACA,EAAsB,uBAAwB,CAC/C,IAAMC,EAAYlC,EAAUyB,EAAM,SAAS,EAC3C,GAAIS,EACA,OAAOC,EAAc,OAAOV,EAAM,IAAK,CACnCW,EAAW,KAAKF,EAAU,IAAKA,EAAU,IAAMA,EAAU,KAAK,SAAU,CACpE,SAAU,OACV,MAAO,0BACP,qBAAsBD,EAAsB,YAChD,CAAC,CACL,CAAC,CAET,CAEA,OAAOE,EAAc,OAAOV,EAAM,IAAK,CACnCW,EAAW,OACPH,EAAsB,cAAiBA,EAAsB,iBAAkB,OAC/EA,EAAsB,cACtB,CACI,SAAU,OACV,MAAO,0BACP,qBAAsBA,EAAsB,YAChD,CACJ,CACJ,CAAC,CACL,CACJ,CACJ,CAAC,CACL,CAEO,SAASZ,EAA0BgB,EAAgD,CACtF,OAAK,KAAK,kBAAkB,SAAShB,CAAgB,GACjD,KAAK,oBAAoBA,CAAgB,EAGtC,KAAK,GAAG,UAAUA,CAAgB,GAAIgB,CAAQ,CACzD,CAiBA,IAAW,OAAQ,CAhSvB,IAAA5B,EAAA6B,EAiSQ,QAAOA,GAAA7B,EAAA,KAAK,OAAL,YAAAA,EAAW,QAAX,YAAA6B,EAAkB,OAAQ,EACrC,CAEJ,EEpSA,OAAS,QAAAC,MAAY,eAEd,IAAMC,EAAeD,EAAK,OAAO,CACpC,KAAM,UACN,OAAQ,GACR,MAAO,SACP,KAAM,GACN,WAAY,GAEZ,eAAgB,CACZ,MAAO,CACH,GAAI,CAAE,QAAS,IAAK,EACpB,MAAO,CAAE,QAAS,IAAK,CAC3B,CACJ,EAEA,WAAY,CACR,MAAO,CACH,CACI,IAAK,2BACT,CACJ,CACJ,EAEA,WAAW,CAAE,KAAAE,CAAK,EAAG,CACjB,MAAO,CACH,OACA,CACI,MAAO,UACP,YAAa,UACb,UAAWA,EAAK,MAAM,GACtB,aAAcA,EAAK,MAAM,MACzB,gBAAiB,OACrB,EACAA,EAAK,MAAM,KACf,CACJ,EAGA,WAAW,CAAE,KAAAA,CAAK,EAAG,CACjB,MAAO,EACX,CACJ,CAAC,ECvCM,SAASC,EACZC,EACAC,EACF,CAEED,EAAO,cAAc,MAAM,EAAE,cAAc,CACvC,KAAM,UACN,MAAO,CACH,GAAIC,EAAK,GACT,MAAOA,EAAK,KAChB,CACJ,CAAC,EAAE,IAAI,CAEX,CChBA,OAAS,UAAAC,EAAQ,aAAAC,MAAiB,oBAI3B,IAAMC,EAAN,KAA0B,CAG7B,YAAYC,EAAiBC,EAA+C,CAF5EC,EAAA,KAAgB,UAGZ,KAAK,OAAS,IAAIC,EAAO,CACrB,IAAK,IAAIC,EAAU,gBAAgB,EAEnC,kBAAkBC,EAAcC,EAAUC,EAAU,CAChD,GAAI,CAACF,EAAa,KAAKG,GAAMA,EAAG,UAAU,EACtC,OAAO,KAGX,IAAMC,EAAc,IAAI,IAClBC,EAAgB,IAAI,IAE1BJ,EAAS,IAAI,YAAYK,GAAQ,CACzBA,EAAK,KAAK,OAAS,WAAaA,EAAK,MAAM,IAC3CF,EAAY,IAAIE,EAAK,MAAM,GAAIA,EAAK,KAAK,CAEjD,CAAC,EAEDJ,EAAS,IAAI,YAAYI,GAAQ,CACzBA,EAAK,KAAK,OAAS,WAAaA,EAAK,MAAM,IAC3CD,EAAc,IAAIC,EAAK,MAAM,EAAE,CAEvC,CAAC,EAED,OAAW,CAACC,EAAIC,CAAK,IAAKJ,EAAY,QAAQ,EACrCC,EAAc,IAAIE,CAAE,GACrBX,GAAA,MAAAA,EAAkB,CACd,GAAIY,EAAM,GACV,MAAOA,EAAM,KACjB,EAGZ,CACJ,CAAC,CACL,CACJ,EPpBA,IAAqBC,EAArB,KAA6B,CAKzB,YAAYC,EAA+B,CAJ3CC,EAAA,sBACAA,EAAA,KAAgB,mBAChBA,EAAA,KAAgB,uBAGZ,KAAK,gBAAkB,IAAIC,EAAgC,IAAI,EAC/D,KAAK,oBAAsB,IAAIC,EAAoB,KAAMH,EAAQ,eAAe,EAEhF,IAAMI,EAAqBC,EAAU,OAAO,CACxC,KAAM,qBACN,sBAAuB,IACZ,CACH,KAAK,gBAAgB,OACrB,KAAK,oBAAoB,MAC7B,CAER,CAAC,EAED,KAAK,cAAgB,IAAIC,EAAO,CAC5B,QAASN,EAAQ,QACjB,QAASA,EAAQ,SAAW,GAC5B,WAAY,CACR,GAAGO,EACHC,EAAQ,UAAU,CACd,MAAO,IACP,cAAe,GACnB,CAAC,EACDC,EACAC,EAAY,UAAU,CAClB,YAAaV,EAAQ,aAAe,wBACpC,iBAAkB,iBACtB,CAAC,EACDW,EAAmB,UAAU,CACzB,YAAaX,EAAQ,WACzB,CAAC,EACDI,CACJ,EACA,SAAU,CAAC,CAAE,OAAAQ,CAAO,IAAM,CACtBZ,EAAQ,SAASY,EAAO,QAAQ,CAAC,CACrC,CACJ,CAAC,CACL,CAGA,SAASC,EAAiB,CACtB,KAAK,cAAc,KAAK,SAASA,CAAE,CACvC,CAEO,kBAAkBC,EAAmB,CACxCC,EAAmB,KAAMD,CAAI,CAUjC,CAEA,IAAW,YAAsB,CAC7B,OAAO,KAAK,cAAc,aAAe,OAAY,GAAO,KAAK,cAAc,UACnF,CAEA,IAAW,YAAa,CACpB,OAAO,KAAK,cAAc,KAAK,GACnC,CAEO,OAAQ,CACX,KAAK,cAAc,SAAS,aAAa,EAAI,EAC7C,KAAK,cAAc,SAAS,MAAM,CACtC,CAEO,qBAA0C,CAC7C,IAAME,EAA+B,CAAC,EAItC,OAFY,KAAK,cAAc,MAAM,IAEjC,YAAY,CAACC,EAAMC,IAAQ,CAtGvC,IAAAC,EAAAC,EAuGgBH,EAAK,KAAK,OAAS,WACnBD,EAAS,KAAK,CACV,IAAIG,EAAAF,EAAK,MAAM,KAAX,KAAAE,EAAiB,KACrB,OAAOC,EAAAH,EAAK,MAAM,QAAX,KAAAG,EAAoB,IAC/B,CAAC,CAET,CAAC,EAEMJ,CACX,CACJ,EQ3GA,IAAOK,GAAQC","names":["Editor","Extension","Document","Paragraph","Text","baseExtensions","History","Placeholder","Extension","Plugin","FileInputExtension","handleFile","file","_a","_b","_","event","items","item","files","findParentNode","Plugin","PluginKey","Decoration","DecorationSet","EventEmitter","__publicField","event","fn","args","callbacks","callback","suggestionMenuPluginKey","PluginKey","findBlock","findParentNode","node","SuggestionMenuView","editor","emitUpdate","__publicField","item","menuName","_a","view","prevState","prev","next","started","stopped","decorationNode","from","to","SuggestionMenuProseMirrorPlugin","EventEmitter","triggerCharacter","c","triggerCharacters","Plugin","state","transaction","_oldState","newState","suggestionPluginTransactionMeta","_from","_to","text","suggestionPluginState","blockNode","DecorationSet","Decoration","callback","_b","Node","MentionBlock","node","InsertMentionBlock","editor","item","Plugin","PluginKey","MentionDeletePlugin","editor","onMentionDelete","__publicField","Plugin","PluginKey","transactions","oldState","newState","tr","oldMentions","newMentionIds","node","id","attrs","MEditor","options","__publicField","SuggestionMenuProseMirrorPlugin","MentionDeletePlugin","MEditorUIExtension","Extension","Editor","baseExtensions","History","MentionBlock","Placeholder","FileInputExtension","editor","tr","item","InsertMentionBlock","mentions","node","pos","_a","_b","index_default","MEditor"]}
1
+ {"version":3,"sources":["../src/editor.ts","../src/schema/base.ts","../src/extensions/FileInput/FileInput.ts","../src/extensions/SuggestionMenu/SuggestionPlugin.ts","../src/utils/EventEmitter.ts","../src/blocks/MentionBlock.ts","../src/api/InsertMentionBlock.ts","../src/extensions/MentionDeletePlugin/MentionDeletePlugin.ts","../src/extensions/ShiftEnterPlugin/ShiftEnterPlugin.ts","../src/index.ts"],"sourcesContent":["import { Editor, Extension } from '@tiptap/core'\nimport { baseExtensions } from './schema/base'\nimport History from '@tiptap/extension-history'\nimport Placeholder from '@tiptap/extension-placeholder'\nimport { FileInputExtension } from './extensions/FileInput/FileInput'\nimport { Transaction } from 'prosemirror-state'\nimport { SuggestionMenuProseMirrorPlugin } from './extensions/SuggestionMenu/SuggestionPlugin'\nimport { MentionBlock } from './blocks/MentionBlock'\nimport { type MentionItem } from './extensions/SuggestionMenu/types'\nimport { InsertMentionBlock } from './api/InsertMentionBlock'\nimport { MentionDeletePlugin } from './extensions/MentionDeletePlugin/MentionDeletePlugin'\nimport { EnterMode } from './extensions/ShiftEnterPlugin/ShiftEnterPlugin'\nimport { ShiftEnterPlugin } from './extensions/ShiftEnterPlugin/ShiftEnterPlugin'\n\nexport interface MentionEditorOptions {\n element: HTMLElement\n onChange: (text: string) => void\n placeholder?: string\n onFileInput?: (file: File) => void\n content?: string\n onMentionDelete?: (item: MentionItem) => void\n onEnter?: () => void\n lineBreak?: EnterMode\n}\n\n\nexport default class MEditor {\n options: MentionEditorOptions\n _tiptapEditor: Editor\n public readonly suggestionMenus: SuggestionMenuProseMirrorPlugin\n public readonly mentionDeletePlugin: MentionDeletePlugin\n public readonly shiftEnterPlugin: ShiftEnterPlugin\n\n constructor(options: MentionEditorOptions) {\n this.options = options\n this.suggestionMenus = new SuggestionMenuProseMirrorPlugin(this)\n this.mentionDeletePlugin = new MentionDeletePlugin(this, options.onMentionDelete)\n this.shiftEnterPlugin = new ShiftEnterPlugin(this, options.onEnter)\n\n const MEditorUIExtension = Extension.create({\n name: 'MEditorUIExtension',\n addProseMirrorPlugins: () => {\n const plugins = [\n this.suggestionMenus.plugin,\n this.mentionDeletePlugin.plugin,\n this.shiftEnterPlugin.plugin,\n ]\n\n return plugins\n },\n })\n\n this._tiptapEditor = new Editor({\n element: options.element,\n content: options.content || '',\n extensions: [\n ...baseExtensions,\n History.configure({\n depth: 100,\n newGroupDelay: 500,\n }),\n MentionBlock,\n Placeholder.configure({\n placeholder: options.placeholder || '请输入...',\n emptyEditorClass: 'is-editor-empty'\n }),\n FileInputExtension.configure({\n onFileInput: options.onFileInput,\n }),\n MEditorUIExtension,\n ],\n onUpdate: ({ editor }) => {\n options.onChange(editor.getText())\n }\n })\n }\n\n\n dispatch(tr: Transaction) {\n this._tiptapEditor.view.dispatch(tr)\n }\n\n public inserMentionBlock(item: MentionItem) {\n InsertMentionBlock(this, item)\n // this._tiptapEditor\n // .chain()\n // .focus()\n // .insertContent({\n // type: 'mention',\n // attrs: item\n // })\n // .insertContent(' ')\n // .run()\n }\n\n public get isEditable(): boolean {\n return this._tiptapEditor.isEditable === undefined ? true : this._tiptapEditor.isEditable\n }\n\n public get domElement() {\n return this._tiptapEditor.view.dom as HTMLDivElement\n }\n\n public clear() {\n this._tiptapEditor.commands.clearContent(true)\n this._tiptapEditor.commands.focus()\n }\n\n public getAllMentionBlocks(): Array<MentionItem> {\n const mentions: Array<MentionItem> = []\n\n const doc = this._tiptapEditor.state.doc\n\n doc.descendants((node, pos) => {\n if (node.type.name === 'mention') {\n mentions.push({\n id: node.attrs.id ?? null,\n label: node.attrs.label ?? null,\n })\n }\n })\n\n return mentions\n }\n}\n","import Document from '@tiptap/extension-document'\nimport Paragraph from '@tiptap/extension-paragraph'\nimport Text from '@tiptap/extension-text'\nimport HardBreak from '@tiptap/extension-hard-break'\n\nexport const baseExtensions = [\n Document,\n Paragraph,\n Text,\n HardBreak,\n]\n","import { Extension } from '@tiptap/core'\nimport { Plugin } from 'prosemirror-state'\nimport { FileInputOptions } from './types'\n\nexport const FileInputExtension = Extension.create<FileInputOptions>({\n name: 'imageInput',\n\n addOptions() {\n return {\n onFileInput: undefined,\n }\n },\n\n addProseMirrorPlugins() {\n const handleFile = async (file: File) => {\n this.options.onFileInput?.(file)\n }\n\n return [\n new Plugin({\n props: {\n handlePaste: (_, event) => {\n const items = event.clipboardData?.items\n if (!items) return false\n\n for (const item of items) {\n if (item.kind !== 'file') continue\n const file = item.getAsFile()\n if (!file) continue\n\n handleFile(file)\n return true\n }\n\n return false\n },\n\n handleDrop: (_, event) => {\n const files = event.dataTransfer?.files\n if (!files || files.length === 0) return false\n\n handleFile(files[0])\n return true\n },\n },\n }),\n ]\n },\n})\n","import { findParentNode } from '@tiptap/core'\r\nimport { EditorState, Plugin, PluginKey } from 'prosemirror-state'\r\nimport { Decoration, DecorationSet, EditorView } from 'prosemirror-view'\r\nimport MEditor from '../../editor'\r\nimport { EventEmitter } from '../../utils/EventEmitter'\r\nimport { SuggestionMenuState, MentionItem } from './types'\r\n\r\ntype SuggestionPluginState =\r\n | {\r\n triggerCharacter: string\r\n deleteTriggerCharacter: boolean\r\n queryStartPos: number\r\n query: string\r\n decorationId: string\r\n ignoreQueryLength?: boolean\r\n }\r\n | undefined\r\n\r\nexport const suggestionMenuPluginKey = new PluginKey('SuggestionMenuPlugin')\r\nconst findBlock = findParentNode(node => node.type.name === 'blockContainer')\r\n\r\nclass SuggestionMenuView {\r\n pluginState: SuggestionPluginState\r\n public state?: SuggestionMenuState\r\n public emitUpdate: (triggerCharacter: string) => void\r\n private rootEl?: Document | ShadowRoot\r\n\r\n constructor(\r\n private readonly editor: MEditor,\r\n emitUpdate: (menuName: string, state: SuggestionMenuState) => void\r\n ) {\r\n this.pluginState = undefined\r\n\r\n this.emitUpdate = (menuName: string) => {\r\n if (!this.state) {\r\n throw new Error('Attempting to update uninitialized suggestions menu')\r\n }\r\n emitUpdate(menuName, {\r\n ...this.state,\r\n ignoreQueryLength: this.pluginState?.ignoreQueryLength,\r\n })\r\n }\r\n setTimeout(() => {\r\n this.rootEl = this.editor._tiptapEditor.view.root\r\n })\r\n\r\n }\r\n\r\n update(view: EditorView, prevState: EditorState) {\r\n\r\n const prev: SuggestionPluginState = suggestionMenuPluginKey.getState(prevState)\r\n const next: SuggestionPluginState = suggestionMenuPluginKey.getState(view.state)\r\n\r\n \r\n const started = prev === undefined && next !== undefined\r\n const stopped = prev !== undefined && next === undefined\r\n const changed = prev !== undefined && next !== undefined\r\n\r\n \r\n if (!started && !changed && !stopped) {\r\n return\r\n }\r\n\r\n this.pluginState = stopped ? prev : next\r\n\r\n if (stopped || !this.editor.isEditable) {\r\n\r\n this.state!.show = false\r\n this.emitUpdate(this.pluginState!.triggerCharacter)\r\n\r\n return\r\n }\r\n\r\n const decorationNode = this.rootEl?.querySelector(`[data-decoration-id=\"${this.pluginState!.decorationId}\"]`)\r\n\r\n if (this.editor.isEditable && decorationNode) {\r\n\r\n this.state = {\r\n show: true,\r\n referencePos: decorationNode.getBoundingClientRect(),\r\n query: this.pluginState!.query,\r\n }\r\n\r\n this.emitUpdate(this.pluginState!.triggerCharacter!)\r\n }\r\n }\r\n\r\n destroy() {\r\n\r\n }\r\n\r\n closeMenu = () => {\r\n this.editor.dispatch(this.editor._tiptapEditor.view.state.tr.setMeta(suggestionMenuPluginKey, null))\r\n }\r\n\r\n clearQuery = () => {\r\n if (this.pluginState === undefined) {\r\n return\r\n }\r\n\r\n this.editor._tiptapEditor\r\n .chain()\r\n .focus()\r\n .deleteRange({\r\n from:\r\n this.pluginState.queryStartPos! -\r\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter!.length : 0),\r\n to: this.editor._tiptapEditor.state.selection.from,\r\n })\r\n .run()\r\n }\r\n\r\n insertMention = (item: MentionItem) => {\r\n this.editor._tiptapEditor\r\n .chain()\r\n .focus()\r\n .insertContent({\r\n type: 'mention',\r\n attrs: item\r\n })\r\n .insertContent(' ')\r\n .run()\r\n }\r\n\r\n getReplaceRange() {\r\n if (!this.pluginState) return null\r\n\r\n const from = this.pluginState.queryStartPos -\r\n (this.pluginState.deleteTriggerCharacter ? this.pluginState.triggerCharacter.length : 0)\r\n\r\n const to = this.editor._tiptapEditor.state.selection.from\r\n\r\n return { from, to }\r\n }\r\n\r\n}\r\n\r\nexport class SuggestionMenuProseMirrorPlugin extends EventEmitter<any> {\r\n public view: SuggestionMenuView\r\n public readonly plugin: Plugin\r\n private triggerCharacters: string[] = []\r\n\r\n constructor(editor: MEditor) {\r\n super()\r\n const triggerCharacters = this.triggerCharacters\r\n\r\n this.plugin = new Plugin({\r\n key: suggestionMenuPluginKey,\r\n view: () => {\r\n this.view = new SuggestionMenuView(editor, (triggerCharacter, state) => {\r\n this.emit(`update ${triggerCharacter}`, state)\r\n })\r\n return this.view\r\n },\r\n state: {\r\n init(): SuggestionPluginState {\r\n return undefined\r\n },\r\n apply(transaction, prev, _oldState, newState): SuggestionPluginState {\r\n const suggestionPluginTransactionMeta: {\r\n triggerCharacter: string\r\n deleteTriggerCharacter?: boolean\r\n ignoreQueryLength?: boolean\r\n } | null = transaction.getMeta(suggestionMenuPluginKey)\r\n\r\n\r\n if (\r\n typeof suggestionPluginTransactionMeta === 'object' &&\r\n suggestionPluginTransactionMeta !== null &&\r\n prev === undefined\r\n ) {\r\n return {\r\n triggerCharacter: suggestionPluginTransactionMeta.triggerCharacter,\r\n deleteTriggerCharacter: suggestionPluginTransactionMeta.deleteTriggerCharacter !== false,\r\n queryStartPos: transaction.selection?.from || newState.selection.from,\r\n query: '',\r\n decorationId: `id_${Math.floor(Math.random() * 0xffffffff)}`,\r\n ignoreQueryLength: suggestionPluginTransactionMeta?.ignoreQueryLength,\r\n }\r\n }\r\n\r\n\r\n if (prev === undefined) {\r\n return prev\r\n }\r\n\r\n\r\n if (\r\n newState.selection.from !== newState.selection.to ||\r\n suggestionPluginTransactionMeta === null ||\r\n transaction.getMeta('focus') ||\r\n transaction.getMeta('blur') ||\r\n transaction.getMeta('pointer') ||\r\n (prev.triggerCharacter !== undefined && newState.selection.from < prev.queryStartPos!)\r\n ) {\r\n\r\n return undefined\r\n }\r\n\r\n const next = { ...prev }\r\n\r\n\r\n next.query = newState.doc.textBetween(prev.queryStartPos!, newState.selection.from)\r\n\r\n return next\r\n }\r\n },\r\n\r\n props: {\r\n // 当用户输入一个 trigger 字符,且当前没有 suggestion 激活时:\r\n // 插件拦截这次输入,自己插入字符,并通过 transaction meta 通知 state 打开 suggestion 菜单;\r\n // 其余情况下,完全不干预编辑器行为。\r\n handleTextInput(view, _from, _to, text) {\r\n\r\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(view.state)\r\n\r\n if (triggerCharacters.includes(text) && suggestionPluginState === undefined) {\r\n view.dispatch(\r\n view.state.tr.insertText(text).scrollIntoView().setMeta(suggestionMenuPluginKey, {\r\n triggerCharacter: text,\r\n })\r\n )\r\n\r\n return true\r\n }\r\n return false\r\n },\r\n\r\n decorations(state) {\r\n const suggestionPluginState: SuggestionPluginState = (this as Plugin).getState(state)\r\n\r\n if (suggestionPluginState === undefined) {\r\n return null\r\n }\r\n\r\n \r\n if (!suggestionPluginState.deleteTriggerCharacter) {\r\n const blockNode = findBlock(state.selection)\r\n if (blockNode) {\r\n return DecorationSet.create(state.doc, [\r\n Decoration.node(blockNode.pos, blockNode.pos + blockNode.node.nodeSize, {\r\n nodeName: 'span',\r\n class: 'bn-suggestion-decorator',\r\n 'data-decoration-id': suggestionPluginState.decorationId,\r\n }),\r\n ])\r\n }\r\n }\r\n \r\n return DecorationSet.create(state.doc, [\r\n Decoration.inline(\r\n suggestionPluginState.queryStartPos! - suggestionPluginState.triggerCharacter!.length,\r\n suggestionPluginState.queryStartPos!,\r\n {\r\n nodeName: 'span',\r\n class: 'bn-suggestion-decorator',\r\n 'data-decoration-id': suggestionPluginState.decorationId,\r\n }\r\n ),\r\n ])\r\n },\r\n }\r\n })\r\n }\r\n\r\n public onUpdate(triggerCharacter: string, callback: (state: SuggestionMenuState) => void) {\r\n if (!this.triggerCharacters.includes(triggerCharacter)) {\r\n this.addTriggerCharacter(triggerCharacter)\r\n }\r\n \r\n return this.on(`update ${triggerCharacter}`, callback)\r\n }\r\n\r\n addTriggerCharacter = (triggerCharacter: string) => {\r\n this.triggerCharacters.push(triggerCharacter)\r\n }\r\n\r\n \r\n removeTriggerCharacter = (triggerCharacter: string) => {\r\n this.triggerCharacters = this.triggerCharacters.filter(c => c !== triggerCharacter)\r\n }\r\n\r\n closeMenu = () => this.view!.closeMenu()\r\n\r\n clearQuery = () => this.view!.clearQuery()\r\n\r\n insertMention = (item: MentionItem) => this.view!.insertMention(item)\r\n\r\n public get shown() {\r\n return this.view?.state?.show || false\r\n }\r\n\r\n}\r\n","type StringKeyOf<T> = Extract<keyof T, string>\ntype CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[]\n ? T[EventName]\n : [T[EventName]]\ntype CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (...props: CallbackType<T, EventName>) => any\n\nexport class EventEmitter<T extends Record<string, any>> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private callbacks: { [key: string]: Function[] } = {}\n\n public on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>) {\n if (!this.callbacks[event]) {\n this.callbacks[event] = []\n }\n\n this.callbacks[event].push(fn)\n\n return () => this.off(event, fn)\n }\n\n protected emit<EventName extends StringKeyOf<T>>(event: EventName, ...args: CallbackType<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n callbacks.forEach(callback => callback.apply(this, args))\n }\n }\n\n public off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>) {\n const callbacks = this.callbacks[event]\n\n if (callbacks) {\n if (fn) {\n this.callbacks[event] = callbacks.filter(callback => callback !== fn)\n } else {\n delete this.callbacks[event]\n }\n }\n }\n\n protected removeAllListeners(): void {\n this.callbacks = {}\n }\n}\n","import { Node } from '@tiptap/core'\n\nexport const MentionBlock = Node.create({\n name: 'mention',\n inline: true,\n group: 'inline',\n atom: true,\n selectable: false,\n\n addAttributes() {\n return {\n id: { default: null },\n label: { default: null },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'span[data-type=\"mention\"]',\n },\n ]\n },\n\n renderHTML({ node }) {\n return [\n 'span',\n {\n class: 'mention',\n 'data-type': 'mention',\n 'data-id': node.attrs.id,\n 'data-label': node.attrs.label,\n contenteditable: 'false', // 非编辑\n },\n node.attrs.label,\n ]\n },\n\n // 新增:确保mention节点可以正确序列化/反序列化\n renderText({ node }) {\n return ''\n },\n})\n\n\n","import { Selection } from 'prosemirror-state'\nimport MEditor from '../editor'\n\nexport function InsertMentionBlock(\n editor: MEditor,\n item: { id: string; label: string }\n) {\n\n editor._tiptapEditor.chain().insertContent({\n type: 'mention',\n attrs: {\n id: item.id,\n label: item.label,\n }\n }).run() \n\n}\n\n","import { Plugin, PluginKey } from 'prosemirror-state'\nimport MEditor from '../../editor'\nimport { MentionItem } from '../SuggestionMenu/types'\n\nexport class MentionDeletePlugin {\n public readonly plugin: Plugin\n\n constructor(editor: MEditor, onMentionDelete?: (item: MentionItem) => void) {\n this.plugin = new Plugin({\n key: new PluginKey('mention-delete'),\n\n appendTransaction(transactions, oldState, newState) {\n if (!transactions.some(tr => tr.docChanged)) {\n return null\n }\n\n const oldMentions = new Map<string, any>()\n const newMentionIds = new Set<string>()\n\n oldState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n oldMentions.set(node.attrs.id, node.attrs)\n }\n })\n\n newState.doc.descendants(node => {\n if (node.type.name === 'mention' && node.attrs.id) {\n newMentionIds.add(node.attrs.id)\n }\n })\n\n for (const [id, attrs] of oldMentions.entries()) {\n if (!newMentionIds.has(id)) {\n onMentionDelete?.({\n id: attrs.id,\n label: attrs.label,\n })\n }\n }\n },\n })\n }\n} \n","import { Plugin, PluginKey } from 'prosemirror-state'\nimport MEditor from '../../editor'\n\nexport const ShiftEnterPluginKey = new PluginKey('ShiftEnterPluginKey')\nexport type EnterMode = 'enter' | 'shift+enter'\n\nexport class ShiftEnterPlugin {\n public readonly plugin: Plugin\n\n constructor(editor: MEditor, onEnter?: () => void) {\n this.plugin = new Plugin({\n key: ShiftEnterPluginKey,\n\n props: {\n handleKeyDown(view, event) {\n\n if (event.key !== 'Enter') {\n return false\n }\n\n const enterMode: EnterMode = editor.options.lineBreak ?? 'enter'\n const isShift = event.shiftKey\n\n // enter模式 enter换行 shift+enter调用onEnter\n // shift+enter模式 shift+enter换行 enter调用onEnter\n const shouldCallOnEnter =\n (enterMode === 'enter' && isShift) ||\n (enterMode === 'shift+enter' && !isShift)\n\n const shouldInsertBreak = !shouldCallOnEnter\n\n // ---------- 调用 onEnter ----------\n if (shouldCallOnEnter) {\n // suggestion 打开时,让 suggestion 处理\n if (editor.suggestionMenus?.shown) {\n return false\n }\n\n if (onEnter) {\n event.preventDefault()\n onEnter()\n return true\n }\n\n return false\n }\n\n // ---------- 默认换行 ----------\n if (shouldInsertBreak) {\n event.preventDefault()\n\n const { state, dispatch } = view\n const { hard_break } = state.schema.nodes\n\n if (!hard_break) {\n return false\n }\n\n dispatch(\n state.tr\n .replaceSelectionWith(hard_break.create())\n .scrollIntoView(),\n )\n\n return true\n }\n\n return false\n },\n },\n\n })\n }\n}","import MEditor from \"./editor\";\n\nexport * from \"./extensions/SuggestionMenu/types\"\nexport * from \"./extensions/FileInput/types\"\n\nexport { MEditor }\nexport default MEditor"],"mappings":"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","names":["Editor","Extension","Document","Paragraph","Text","HardBreak","baseExtensions","History","Placeholder","Extension","Plugin","FileInputExtension","handleFile","file","_a","_b","_","event","items","item","files","findParentNode","Plugin","PluginKey","Decoration","DecorationSet","EventEmitter","__publicField","event","fn","args","callbacks","callback","suggestionMenuPluginKey","PluginKey","findBlock","findParentNode","node","SuggestionMenuView","editor","emitUpdate","__publicField","item","menuName","_a","view","prevState","prev","next","started","stopped","decorationNode","from","to","SuggestionMenuProseMirrorPlugin","EventEmitter","triggerCharacter","c","triggerCharacters","Plugin","state","transaction","_oldState","newState","suggestionPluginTransactionMeta","_from","_to","text","suggestionPluginState","blockNode","DecorationSet","Decoration","callback","_b","Node","MentionBlock","node","InsertMentionBlock","editor","item","Plugin","PluginKey","MentionDeletePlugin","editor","onMentionDelete","__publicField","Plugin","PluginKey","transactions","oldState","newState","tr","oldMentions","newMentionIds","node","id","attrs","Plugin","PluginKey","ShiftEnterPluginKey","PluginKey","ShiftEnterPlugin","editor","onEnter","__publicField","Plugin","view","event","_a","_b","enterMode","isShift","shouldCallOnEnter","shouldInsertBreak","state","dispatch","hard_break","MEditor","options","__publicField","SuggestionMenuProseMirrorPlugin","MentionDeletePlugin","ShiftEnterPlugin","MEditorUIExtension","Extension","Editor","baseExtensions","History","MentionBlock","Placeholder","FileInputExtension","editor","tr","item","InsertMentionBlock","mentions","node","pos","_a","_b","index_default","MEditor"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shenjipo/mention-editor",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,7 +11,8 @@
11
11
  }
12
12
  },
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "src"
15
16
  ],
16
17
  "publishConfig": {
17
18
  "access": "public"
@@ -26,6 +27,7 @@
26
27
  "@tiptap/extension-paragraph": "2.7.1",
27
28
  "@tiptap/extension-placeholder": "2.7.1",
28
29
  "@tiptap/extension-text": "2.7.1",
30
+ "@tiptap/extension-hard-break": "2.7.1",
29
31
  "prosemirror-model": "^1.21.0",
30
32
  "prosemirror-state": "^1.4.3",
31
33
  "prosemirror-view": "^1.33.7"
@@ -0,0 +1,18 @@
1
+ import { Selection } from 'prosemirror-state'
2
+ import MEditor from '../editor'
3
+
4
+ export function InsertMentionBlock(
5
+ editor: MEditor,
6
+ item: { id: string; label: string }
7
+ ) {
8
+
9
+ editor._tiptapEditor.chain().insertContent({
10
+ type: 'mention',
11
+ attrs: {
12
+ id: item.id,
13
+ label: item.label,
14
+ }
15
+ }).run()
16
+
17
+ }
18
+
@@ -0,0 +1,45 @@
1
+ import { Node } from '@tiptap/core'
2
+
3
+ export const MentionBlock = Node.create({
4
+ name: 'mention',
5
+ inline: true,
6
+ group: 'inline',
7
+ atom: true,
8
+ selectable: false,
9
+
10
+ addAttributes() {
11
+ return {
12
+ id: { default: null },
13
+ label: { default: null },
14
+ }
15
+ },
16
+
17
+ parseHTML() {
18
+ return [
19
+ {
20
+ tag: 'span[data-type="mention"]',
21
+ },
22
+ ]
23
+ },
24
+
25
+ renderHTML({ node }) {
26
+ return [
27
+ 'span',
28
+ {
29
+ class: 'mention',
30
+ 'data-type': 'mention',
31
+ 'data-id': node.attrs.id,
32
+ 'data-label': node.attrs.label,
33
+ contenteditable: 'false', // 非编辑
34
+ },
35
+ node.attrs.label,
36
+ ]
37
+ },
38
+
39
+ // 新增:确保mention节点可以正确序列化/反序列化
40
+ renderText({ node }) {
41
+ return ''
42
+ },
43
+ })
44
+
45
+