@veltdev/lexical-velt-comments 1.0.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/cjs/index.js +2 -0
- package/cjs/index.js.map +1 -0
- package/cjs/types/comment-node.d.ts +23 -0
- package/cjs/types/constants.d.ts +6 -0
- package/cjs/types/editor.d.ts +384 -0
- package/cjs/types/index.d.ts +24 -0
- package/cjs/types/plugin.d.ts +14 -0
- package/cjs/types/serializer.d.ts +9 -0
- package/cjs/types/store.d.ts +39 -0
- package/cjs/types/types.d.ts +40 -0
- package/cjs/types/velt.d.ts +21 -0
- package/esm/index.js +2 -0
- package/esm/index.js.map +1 -0
- package/esm/types/comment-node.d.ts +23 -0
- package/esm/types/constants.d.ts +6 -0
- package/esm/types/editor.d.ts +384 -0
- package/esm/types/index.d.ts +24 -0
- package/esm/types/plugin.d.ts +14 -0
- package/esm/types/serializer.d.ts +9 -0
- package/esm/types/store.d.ts +39 -0
- package/esm/types/types.d.ts +40 -0
- package/esm/types/velt.d.ts +21 -0
- package/index.d.ts +58 -0
- package/package.json +44 -0
package/cjs/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var t,e=require("lexical");class n extends e.ElementNode{static getType(){return"comment"}static clone(t){return new n(t.__annotationId,t.__multiThreadAnnotationId,t.__key)}constructor(t,e,n){super(n),this.__annotationId=t,this.__multiThreadAnnotationId=e}createDOM(t){const e=document.createElement("velt-comment-text");return this.__annotationId&&e.setAttribute("annotation-id",this.__annotationId),this.__multiThreadAnnotationId&&e.setAttribute("multi-thread-annotation-id",this.__multiThreadAnnotationId),e}updateDOM(t,e,n){return!1}static importJSON(t){return r(t.annotationId,t.multiThreadAnnotationId)}exportJSON(){return{...super.exportJSON(),annotationId:this.__annotationId,multiThreadAnnotationId:this.__multiThreadAnnotationId,type:"comment",version:1}}isInline(){return!0}}function r(t,e){return new n(t,e)}function o(t){return t instanceof n}class i{}t=i,i.selectedCommentsMap=new Map,i.subscribers=new Map,i.isSubscribed=!1,i.getCommentElement=()=>{try{const t=window.Velt;return t?.getCommentElement?t.getCommentElement():null}catch(e){return t.catchError("Error getting comment element:",e),null}},i.addManualComment=({context:e,location:n})=>{try{const r=t.getCommentElement();return r?r.addManualComment({context:e,location:n}):Promise.resolve(null)}catch(e){return t.catchError("Error adding manual comment:",e),Promise.resolve(null)}},i.updateContext=({annotationId:e,context:n})=>{try{const r=t.getCommentElement();return r?r.updateContext(e,n):Promise.resolve(null)}catch(e){t.catchError("Error updating context:",e)}},i.subscribeToSelectedCommentsMap=(e,n)=>{try{t.subscribeToSelectedAnnotationsMapSingleton(),t.subscribers.set(e,n)}catch(e){t.catchError("Error subscribing to selected comments map:",e)}},i.unsubscribeFromSelectedCommentsMap=e=>{try{t.subscribers.delete(e)}catch(e){t.catchError("Error unsubscribing from selected comments map:",e)}},i.catchError=(t,e)=>{try{let n={};e&&"object"==typeof e&&(n={...n,...e}),t&&(n.message=t),n.sdkVersion=window.Velt?.version}catch(t){}},i.subscribeToSelectedAnnotationsMapSingleton=()=>{try{if(t.isSubscribed)return;const e=t.getCommentElement();e&&"function"==typeof e?.getSelectedComments&&(e?.getSelectedComments()?.subscribe(e=>{const n=new Map;e?.forEach(t=>{t?.annotationId&&n.set(t?.annotationId,!0)});((t,e)=>{if(t.size!==e.size)return!1;for(const[n,r]of t)if(e.get(n)!==r)return!1;return!0})(n,t.selectedCommentsMap||new Map)||t.updateSelectedCommentsMap(n)}),t.isSubscribed=!0)}catch(t){return new Map}},i.updateSelectedCommentsMap=e=>{try{t.selectedCommentsMap=e,t.subscribers.forEach(e=>{"function"==typeof e&&e(t.selectedCommentsMap)})}catch(e){t.catchError("Error updating selected comments map:",e)}};class a{constructor(t){this.plugin=t}initializeTransactionListener(t){try{this.editorUpdateListenerRemover&&this.editorUpdateListenerRemover(),this.editorUpdateListenerRemover=t.registerUpdateListener(({editorState:e,prevEditorState:n})=>{try{if(e===n||!this.hasDocumentChanged(e,n))return;this.onTransaction(t)}catch(t){}})}catch(t){i.catchError("Error initializing transaction listener:",t)}}destroyTransactionListener(){try{this.editorUpdateListenerRemover&&(this.editorUpdateListenerRemover(),this.editorUpdateListenerRemover=void 0)}catch(t){i.catchError("Error destroying transaction listener:",t)}}hasDocumentChanged(t,n){try{return t.read(()=>{const t=e.$getRoot().getTextContent();return n.read(()=>{const n=e.$getRoot().getTextContent();return t!==n})})}catch(t){return!0}}onTransaction(t){try{const e=new Map,n=this.collectDocumentAnnotations(t);for(const[r,o]of Array.from(n.entries())){const n=this.processAnnotationChanges(t,o);n&&e.set(r,n)}if(e.size>0){const n=i.getCommentElement();if(!n)return;this.updateVeltComments(n,e,t)}}catch(t){i.catchError("Error in onTransaction:",t)}}getCommentNodeTextWithStructure(t){try{let n="";const r=(t,o=0)=>{if(e.$isTextNode(t))n+=t.getTextContent();else if(e.$isElementNode(t)){const i=t.getChildren(),a=t.getType();for(let t=0;t<i.length;t++)r(i[t],o+1);if("paragraph"===a&&o>=0){const r=t.getParent();if(r&&e.$isElementNode(r)){const e=r.getChildren();e.indexOf(t)<e.length-1&&(n+="\n")}}}};return r(t),n}catch(e){return t.getTextContent()}}collectDocumentAnnotations(t){try{const n=new Map,r=this;return t.getEditorState().read(()=>{const t=e.$getRoot();let i=0;const a=t=>{if(o(t)){const e=t.__annotationId;if(!e)return;const o=r.plugin.storeService.annotationStore.get(e);if(!o)return;const a=r.getCommentNodeTextWithStructure(t),c=a.length,s=n.get(e),d={node:{text:a,nodeSize:c},pos:i};s?s.nodes.push(d):n.set(e,{id:e,multiThreadAnnotationId:t.__multiThreadAnnotationId,annotation:o.annotation,nodes:[d],originalText:o.annotation.context?.textEditorConfig?.text||"",originalOccurrence:o.annotation.context?.textEditorConfig?.occurrence||1,targetTextNodeId:o.annotation.context?.textEditorConfig?.targetTextNodeId||""}),i+=c}else if(e.$isTextNode(t))i+=t.getTextContent().length;else if(e.$isElementNode(t)){const e=t.getChildren();for(const t of e)a(t)}};a(t)}),n}catch(t){return i.catchError("Error collecting document annotations:",t),new Map}}processAnnotationChanges(t,e){try{if(!t||!e)throw new Error("Invalid input: editor and data are required");if(!e.originalText||!e.annotation)return null;if(!Array.isArray(e.nodes)||0===e.nodes.length)return null;const{currentText:n,contentChanged:r}=this.detectContentChanges(e.nodes,e.originalText),{targetTextNodeIdChanged:o,newTargetTextNodeId:i,searchResults:a}=this.detectContainerChanges(t,{annotationId:e.id,currentText:n,targetTextNodeId:e.targetTextNodeId,nodes:e.nodes}),c=this.calculateNewOccurrence(t,{searchResults:a,nodes:e.nodes,contentChanged:r,currentText:n,targetTextNodeId:o?i:e.targetTextNodeId,originalOccurrence:e.originalOccurrence}),s=c!==e.originalOccurrence;return r||s||o?this.createAnnotationChange(e,{currentText:n,contentChanged:r,currentOccurrence:c,occurrenceChanged:s,targetTextNodeIdChanged:o,newTargetTextNodeId:i}):null}catch(t){return i.catchError("Error processing annotation changes:",t),null}}detectContentChanges(t,e){const n=[...t].sort((t,e)=>t.pos-e.pos),r=n.length>1&&e.includes("\n")?n.map(t=>t.node.text||"").join("\n"):n.map(t=>t.node.text||"").join("");return{currentText:r,contentChanged:r!==e}}detectContainerChanges(t,e){const{annotationId:n,currentText:r,targetTextNodeId:o,nodes:i}=e;let a=!1,c=o,s=[];const d=this.processContainerChanges(t,{annotationId:n,currentText:r,targetTextNodeId:o,nodes:i});return d?(a=d.changed,c=d.newId,s=d.searchResults):s=o?this.findTextInDomElement(t,r,o,void 0):this.findTextInDocument(t,r,void 0),{targetTextNodeIdChanged:a,newTargetTextNodeId:c,searchResults:s}}processContainerChanges(t,n){const{annotationId:r,currentText:i,targetTextNodeId:a}=n;if(!a)return null;let c=null;if(t.getEditorState().read(()=>{const t=e.$getRoot();let n=0;!function t(i){if(o(i)&&i.__annotationId===r)c=n;else if(e.$isTextNode(i))n+=i.getTextContent().length;else if(e.$isElementNode(i)){const e=i.getChildren();for(const n of e)if(t(n),null!==c)return}}(t)}),null!==c){const e=t.getRootElement();if(!e)return null;if(e.querySelector(`#${a}`)){if(0===this.findTextInDomElement(t,i,a,void 0).length){const e=this.findNewContainer(t,i);if(e&&e.id!==a){const n=this.findTextInDomElement(t,i,e.id,void 0);return{changed:!0,newId:e.id,searchResults:n}}}}}return null}findNewContainer(t,e){const n=t.getRootElement();if(!n)return null;const r=n.querySelectorAll("[id]");for(const t of Array.from(r))if(t.textContent?.includes(e))return t;return null}calculateNewOccurrence(t,e){if(0===e.searchResults.length)return e.originalOccurrence;const n=e.nodes[0],r=e.nodes[e.nodes.length-1],o=n.pos,i=r.pos+(r.node.nodeSize||0);for(let t=0;t<e.searchResults.length;t++){const n=e.searchResults[t];if(n.start<=o&&n.end>=o||n.start<=i&&n.end>=i||o<=n.start&&i>=n.end)return t+1}return e.originalOccurrence}createAnnotationChange(t,e){const{currentText:n,contentChanged:r,currentOccurrence:o,occurrenceChanged:i,targetTextNodeIdChanged:a,newTargetTextNodeId:c}=e;return{annotationId:t.id,multiThreadAnnotationId:t.multiThreadAnnotationId,originalText:t.originalText,currentText:r?n:t.originalText,originalOccurrence:t.originalOccurrence,currentOccurrence:o,originalTargetTextNodeId:t.targetTextNodeId,newTargetTextNodeId:a?c:t.targetTextNodeId,annotation:t.annotation,contentChanged:r,occurrenceChanged:i,targetTextNodeIdChanged:a}}async updateVeltComments(t,e,n){try{for(const[t,r]of Array.from(e.entries()))try{if(!r.annotation.context?.textEditorConfig)continue;const e=JSON.parse(JSON.stringify(r.annotation.context.textEditorConfig));r.contentChanged&&(e.text=r.currentText),r.occurrenceChanged&&(e.occurrence=r.currentOccurrence),r.targetTextNodeIdChanged&&(e.targetTextNodeId=r.newTargetTextNodeId);const o={...r.annotation.context,textEditorConfig:e};this.plugin.storeService.annotationStore.remove(t),this.removeVeltCommentFromEditor(n,t),await new Promise(t=>setTimeout(t,100)),i.updateContext({annotationId:t,context:o})}catch(t){i.catchError("Error updating individual Velt comment:",t)}}catch(t){i.catchError("Error updating Velt comments:",t)}}getSelectedText(t){return t.getEditorState().read(()=>{const t=e.$getSelection();return e.$isRangeSelection(t)?t.getTextContent():""})}findOccurrenceIndex(t,n,r){try{if(!n.trim())return 1;let o=[],i=0,a=0;t.getEditorState().read(()=>{const c=e.$getSelection();if(e.$isRangeSelection(c)){const e=this.getSelectionTextRange(t,c);i=e.start,a=e.end,o=r&&r.id?this.findTextInContainer(t,n,r.id):this.findTextInEditor(t,n)}});for(let t=0;t<o.length;t++)if(o[t].start===i&&o[t].end===a)return t+1;return 1}catch(t){return i.catchError("Error finding occurrence index:",t),1}}getSelectionTextRange(t,n){const r=e.$getRoot(),{nodeMap:o}=this.collectTextContent(r),i=n.anchor.getNode(),a=n.focus.getNode(),c=n.anchor.offset,s=n.focus.offset;let d=0,l=0;for(const t of o){if(t.isParagraphBreak||!t.node)continue;const e=t.node.getKey();e===i.getKey()&&(d=t.start+c),e===a.getKey()&&(l=t.start+s)}return{start:Math.min(d,l),end:Math.max(d,l)}}collectTextContent(t){try{const n=[];let r="",o=0;const i=(t,a=0)=>{if(e.$isTextNode(t)){const e=t.getTextContent(),i=o,a=o+e.length;n.push({node:t,start:i,end:a}),r+=e,o+=e.length}else if(e.$isElementNode(t)){const c=t.getChildren(),s=t.getType();for(let t=0;t<c.length;t++)i(c[t],a+1);if("paragraph"===s&&1===a){const i=t.getParent();if(i&&e.$isElementNode(i)){const e=i.getChildren();if(e.indexOf(t)<e.length-1){const t=o,e=o+1;n.push({node:null,start:t,end:e,isParagraphBreak:!0}),r+="\n",o+=1}}}}};return i(t),{combinedText:r,nodeMap:n}}catch(t){return i.catchError("Error collecting text content:",t),{combinedText:"",nodeMap:[]}}}findTextInEditor(t,n){try{const r=[];return t.getEditorState().read(()=>{const t=e.$getRoot(),{combinedText:o}=this.collectTextContent(t),i=this.kmpSearch(o,n);for(const t of i)r.push({start:t,end:t+n.length})}),r}catch(t){return i.catchError("Error finding text in editor:",t),[]}}findTextInContainer(t,n,r){try{const o=[],i=document.getElementById(r);return i?(t.getEditorState().read(()=>{const r=e.$getRoot(),{combinedText:a,nodeMap:c}=this.collectTextContent(r),s=this.getContainerTextContent(i,t,c,a);if(!s)return;const d=this.kmpSearch(s.text,n);for(const t of d)o.push({start:s.startOffset+t,end:s.startOffset+t+n.length})}),o):o}catch(t){return i.catchError("Error finding text in container:",t),[]}}getContainerTextContent(t,e,n,r){try{let o=-1,i=-1;for(let r=0;r<n.length;r++){const a=n[r];if(!a.isParagraphBreak&&a.node)try{const n=a.node.getKey(),r=e.getElementByKey(n);r&&t.contains(r)&&(-1===o&&(o=a.start),i=a.end)}catch(t){continue}}if(-1===o||-1===i)return null;return{text:r.substring(o,i),startOffset:o}}catch(t){return null}}filterNodesInContainer(t,e,n){try{const r=[];for(const o of t)try{const t=o.node.getKey(),i=n.getElementByKey(t);i&&e.contains(i)&&r.push(o)}catch(t){continue}return r}catch(t){return[]}}collectTextNodes(t){try{const n=[];let r=0;const o=t=>{if(e.$isTextNode(t)){const e=t.getTextContent();n.push({node:t,text:e,textOffset:r}),r+=e.length}else if(e.$isElementNode(t)){const e=t.getChildren();for(const t of e)o(t)}};return o(t),n}catch(t){return[]}}getTextNodesInRange(t,e,n,r){try{const i=[],{combinedText:a,nodeMap:c}=this.collectTextContent(t);for(const t of c){if(t.isParagraphBreak||!t.node)continue;const a=t.node.getParent();if((!o(a)||!r||a.__annotationId!==r)&&(t.end>e&&t.start<n)){const r=Math.max(0,e-t.start),o=Math.min(t.node.getTextContent().length,n-t.start),a=r>0||o<t.node.getTextContent().length;i.push({node:t.node,startOffset:r,endOffset:o,isPartial:a})}}return i}catch(t){return i.catchError("Error getting text nodes in range:",t),[]}}isRangeAlreadyWrapped(t,n,r,i){try{let a=0,c=!1;const s=t=>{if(o(t)){if(t.__annotationId===i){const e=t.getTextContent(),o=a,i=a+e.length;if(o<=n&&i>=r)return c=!0,!0}const e=t.getTextContent();a+=e.length}else if(e.$isTextNode(t)){const e=t.getTextContent();a+=e.length}else if(e.$isElementNode(t)){const n=t.getChildren();for(const t of n)if(s(t))return!0;if("paragraph"===t.getType()){const n=t.getParent();if(n&&e.$isElementNode(n)){const e=n.getChildren();e.indexOf(t)<e.length-1&&(a+=1)}}}return!1};return s(t),c}catch(t){return!0}}collectTextNodesInRange(t,n){try{const r=[];let o=0;const i=t=>{const a=o;if(e.$isTextNode(t)){const e=t.getTextContent(),i=o+e.length;i>=n.start&&a<=n.end&&r.push({node:t,text:e,start:o,end:i}),o=i}else if(e.$isElementNode(t)){const e=t.getChildren();for(const t of e)i(t)}};return i(t),r}catch(t){return[]}}getContainerRange(t,e){try{const n=t.getRootElement();if(!n||!n.contains(e))return null;const r=e.textContent||"",o=(n.textContent||"").indexOf(r);return-1===o?null:{start:o,end:o+r.length}}catch(t){return i.catchError("Error getting container range:",t),null}}kmpSearch(t,e,n=0,r){try{const o=[];if(!e||!t||e.length>t.length)return o;const i=this.computeKMPTable(e);let a=0,c=0;for(;a<t.length;)if(e[c]===t[a]&&(a++,c++),c===e.length){if(o.push(n+a-c),c=i[c-1],r&&o.length>=r)break}else a<t.length&&e[c]!==t[a]&&(0!==c?c=i[c-1]:a++);return o}catch(t){return[]}}computeKMPTable(t){try{const e=new Array(t.length).fill(0);let n=0,r=1;for(;r<t.length;)t[r]===t[n]?(n++,e[r]=n,r++):0!==n?n=e[n-1]:(e[r]=0,r++);return e}catch(t){return[]}}findParentContainerWithId(t,e){try{const n=t.anchor.getNode(),r=e.getElementByKey(n.getKey());if(!r)return null;let o=r;for(;o&&o!==document.body;){if(o.id)return o;o=o.parentElement}return null}catch(t){return null}}highlightTextWithVeltComment(t,n,r){try{const{targetTextNodeId:o}=r,i=r?.occurrence||1;if(r.annotationId){const e=this.plugin.storeService.annotationStore.get(r.annotationId);if(e){const n=e.annotation.context?.textEditorConfig,o=r.originalAnnotation?.context?.textEditorConfig;n&&o&&(n.text!==o.text||n.occurrence!==o.occurrence||n.targetTextNodeId!==o.targetTextNodeId)&&this.removeVeltCommentFromEditor(t,r.annotationId)}}if(!n||0===n.length)return;if(o){const t=document.getElementById(o);if(t){const e=t.closest("[data-velt-location-id]")?.getAttribute("data-velt-location-id");if(e!==r.originalAnnotation?.location?.id)return}}let a=[];if(a=o?this.findTextInDomElement(t,n,o,i):this.findTextInDocument(t,n,i),0===a.length)return;const c=a[Math.min(i,a.length)-1];if(c&&r.annotationId){if(t.getEditorState().read(()=>{const t=e.$getRoot();return this.isRangeAlreadyWrapped(t,c.start,c.end,r.annotationId)}))return;this.plugin.storeService.annotationStore.set(r.annotationId,{annotation:r.originalAnnotation||{annotationId:r.annotationId,multiThreadAnnotationId:r.multiThreadAnnotationId,text:n},pluginReference:{node:document.createElement("velt-comment-text"),position:{from:c.start,to:c.end}}}),this.setVeltComment(t,r.annotationId,r.multiThreadAnnotationId,c.start,c.end)}}catch(t){i.catchError("Error highlighting text with Velt comment:",t)}}findTextInDomElement(t,n,r,o){try{const i=[],a=document.getElementById(r);return a?(t.getEditorState().read(()=>{const r=e.$getRoot(),c=this.filterNodesInContainer(this.collectTextNodes(r),a,t);if(0===c.length)return;const s=c[0].textOffset,d=c.map(t=>t.text).join(""),l=this.kmpSearch(d,n,0,o);for(const t of l)i.push({start:s+t,end:s+t+n.length})}),i):i}catch(t){return[]}}findTextInDocument(t,n,r){try{const o=[];return t.getEditorState().read(()=>{const t=e.$getRoot(),{combinedText:i}=this.collectTextContent(t),a=this.kmpSearch(i,n,0,r);for(const t of a)o.push({start:t,end:t+n.length})}),o}catch(t){return i.catchError("Error finding text in document:",t),[]}}setVeltComment(t,n,o,a,c){try{t.update(()=>{const t=e.$getRoot();t.selectStart();const i=this.getTextNodesInRange(t,a,c,n);if(0===i.length)return;const s=r(n,o);if(1===i.length){const{node:t,startOffset:e,endOffset:n,isPartial:r}=i[0];r?this.wrapPartialTextNode(t,e,n,s):this.wrapEntireTextNode(t,s)}else this.wrapMultipleTextNodesWithFormatting(i,s)})}catch(t){i.catchError("Error setting Velt comment:",t)}}wrapPartialTextNode(t,n,r,o){try{const i=t.getWritable(),a=i.getTextContent(),c=a.substring(0,n),s=a.substring(n,r),d=a.substring(r),l=e.$createTextNode(s);if(l.setFormat(i.getFormat()),l.setStyle(i.getStyle()),o.append(l),c){const t=e.$createTextNode(c);t.setFormat(i.getFormat()),t.setStyle(i.getStyle()),i.insertBefore(t)}if(i.insertBefore(o),d){const t=e.$createTextNode(d);t.setFormat(i.getFormat()),t.setStyle(i.getStyle()),i.insertBefore(t)}i.remove()}catch(t){}}wrapEntireTextNode(t,e){try{const n=t.getWritable();e.append(n);const r=n.getParent();if(r){const t=r.getWritable(),o=n.getIndexWithinParent();t.splice(o,1,[e])}}catch(t){}}wrapMultipleTextNodesWithFormatting(t,e){try{const n=new Map;for(const e of t){const t=this.findParagraphParent(e.node),r=t?t.getKey():"no-paragraph";n.has(r)||n.set(r,[]),n.get(r).push(e)}let o=!0;for(const[,t]of n.entries()){const n=o?e:r(e.__annotationId,e.__multiThreadAnnotationId);if(1===t.length){const e=t[0],{node:r,startOffset:o,endOffset:i,isPartial:a}=e;a?this.wrapPartialTextNode(r,o,i,n):this.wrapEntireTextNode(r,n)}else this.wrapMultipleNodesInSameParagraph(t,n);o=!1}}catch(t){i.catchError("Error in wrapMultipleTextNodesWithFormatting:",t)}}findParagraphParent(t){let n=t.getParent();for(;n;){if(e.$isElementNode(n)&&"paragraph"===n.getType())return n;n=n.getParent()}return null}wrapMultipleNodesInSameParagraph(t,n){try{const r=[...t].sort((t,e)=>t.node.getIndexWithinParent()-e.node.getIndexWithinParent()),o=r[0],i=r[r.length-1],a=o.node.getWritable(),c=a.getParent();if(!c)return;const s=c.getWritable();let d=a.getIndexWithinParent();if(o.isPartial&&o.startOffset>0){const t=o.node.getTextContent().substring(0,o.startOffset),r=o.node.getTextContent().substring(o.startOffset),i=e.$createTextNode(t);i.setFormat(a.getFormat()),i.setStyle(a.getStyle());const c=e.$createTextNode(r);c.setFormat(a.getFormat()),c.setStyle(a.getStyle()),n.append(c),s.splice(d,1,[i,n])}else n.append(a),s.splice(d,1,[n]);for(let t=1;t<r.length-1;t++){const e=r[t].node.getWritable();n.append(e)}if(r.length>1){const t=i.node.getWritable();if(i.isPartial&&i.endOffset<i.node.getTextContent().length){const r=i.node.getTextContent().substring(0,i.endOffset),o=i.node.getTextContent().substring(i.endOffset),a=e.$createTextNode(r);a.setFormat(t.getFormat()),a.setStyle(t.getStyle());const c=e.$createTextNode(o);c.setFormat(t.getFormat()),c.setStyle(t.getStyle()),n.append(a),t.replace(c)}else n.append(t)}}catch(t){i.catchError("Error in wrapMultipleNodesInSameParagraph:",t)}}removeVeltCommentFromEditor(t,n){try{if(!t||!n)throw new Error("Invalid input: editor and annotationId are required");let r=!1;return t.update(()=>{const t=e.$getRoot(),a=[];!function t(r){if(o(r))r.__annotationId===n&&a.push(r);else if(e.$isElementNode(r)){const e=r.getChildren();for(const n of e)t(n)}}(t);for(const t of a)try{const n=t.getWritable(),o=n.getChildren();if(o.length>0){const t=o[0];n.replace(t);let e=t;for(let t=1;t<o.length;t++)e.insertAfter(o[t]),e=o[t]}else{const t=n.getTextContent();if(t){const r=e.$createTextNode(t);n.replace(r)}else n.remove()}r=!0}catch(t){i.catchError("Error removing individual comment node:",t)}}),r&&this.plugin.storeService.annotationStore.remove(n),r}catch(t){return!1}}}a.getEditorId=t=>{try{return t&&t._config?t._config.namespace:null}catch(t){return i.catchError("Error finding editor ID:",t),null}};class c{constructor(t){this.isSubscribed=!1,this.globalStore={editor:null,comments:[],filteredComments:[],selectedCommentsMap:new Map},this.globalAnnotationStore=new Map,this.annotationStore={get:t=>this.globalAnnotationStore.get(t),set:(t,e)=>{this.globalAnnotationStore.set(t,e)},getAll:()=>new Map(this.globalAnnotationStore),clear:()=>{this.globalAnnotationStore.clear()},remove:t=>{this.globalAnnotationStore.delete(t)},hasAnnotationTextChanged:(t,e)=>{try{const n=this.globalAnnotationStore.get(t);if(!n||!e)return!1;const r=n.annotation.text,o=e.context?.textEditorConfig?.text;return r!==o}catch(t){return!1}}},this.updateGlobalStore=t=>{try{const e=t?.comments||this.globalStore?.comments||[],n=t?.selectedCommentsMap||this.globalStore?.selectedCommentsMap||new Map,r=this.globalStore?.filteredComments||[],o=e.filter(t=>"terminal"!==t?.status?.type||n?.get(t?.annotationId)),i=new Set(o.map(t=>t?.annotationId));r.map(t=>t?.annotationId).filter(t=>t&&!i.has(t)).forEach(t=>{this.globalStore?.editor&&t&&this.plugin.editorService.removeVeltCommentFromEditor(this.globalStore?.editor,t)}),this.globalStore={...this.globalStore,...t,filteredComments:o},this.highlightCommentsFromGlobalStore()}catch(t){i.catchError("Error updating global store:",t)}},this.highlightCommentsFromGlobalStore=()=>{try{const{editor:t,filteredComments:e}=this.globalStore;if(!t||!e)return;for(const n of e){const e=n?.context?.textEditorConfig?.text,r=n?.context?.textEditorConfig?.occurrence;e&&this.plugin.editorService.highlightTextWithVeltComment(t,e,{annotationId:n?.annotationId,multiThreadAnnotationId:n?.multiThreadAnnotationId,occurrence:r,targetTextNodeId:n?.context?.textEditorConfig?.targetTextNodeId,originalAnnotation:n})}}catch(t){i.catchError("Error highlighting comments from global store:",t)}},this.plugin=t;try{i.subscribeToSelectedCommentsMap(this.plugin.editorId,t=>{try{this.updateGlobalStore({selectedCommentsMap:t})}catch(t){i.catchError("Error updating global store:",t)}})}catch(t){i.catchError("Error subscribing to selected comments map:",t)}}}c.storeInstanceMap=new Map;const s=new Map;class d{constructor(t,e){this.editorId=t,this.editor=e,this.editorService=new a(this),e&&this.editorService.initializeTransactionListener(e),this.storeService=new c(this)}static getInstance(t){let{editorId:e,editor:n}=t||{};return e||(e="default"),s.has(e)||s.set(e,new d(e,n)),s.get(e)}}function l(t){const n=function(t){const n=t._createEditorArgs,r={namespace:`shadow-editor-${Date.now()}`,nodes:n?.nodes||[],theme:{},onError:t=>{},editable:!1};return e.createEditor(r)}(t);try{const r=t.getEditorState();n.setEditorState(r),n.update(()=>{!function(t){const n=[];function r(t){if(o(t))n.push(t);else if(e.$isElementNode(t)){t.getChildren().forEach(r)}}r(t),n.forEach(t=>{try{const e=t.getParent();if(!e)return;const n=t.getChildren(),r=t.getIndexWithinParent();t.remove(),n.length>0&&e.splice(r,0,n)}catch(t){}}),t.markDirty()}(e.$getRoot())},{discrete:!0});const i=n.getEditorState().toJSON();return JSON.stringify(i)}catch(e){return function(t){return t.getEditorState().read(()=>{const e=h(g(t.getEditorState().toJSON()));return JSON.stringify(e)})}(t)}}function g(t){if(!t||"object"!=typeof t)return t;if(Array.isArray(t)){const e=[];for(const n of t)if(n&&"comment"===n.type){if(n.children&&Array.isArray(n.children))for(const t of n.children)e.push(g(t))}else e.push(g(n));return e}const e={...t};if("comment"===e.type)return e.children&&Array.isArray(e.children)?e.children.map(t=>g(t)):null;for(const[t,n]of Object.entries(e))("children"===t&&Array.isArray(n)||"object"==typeof n&&null!==n)&&(e[t]=g(n));return e}function h(t){if(!t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(t=>h(t));const e={...t};if(e.children&&Array.isArray(e.children)){const t=e.children.map(t=>h(t));e.children=function(t){if(!Array.isArray(t)||t.length<=1)return t;const e=[];let n=0;for(;n<t.length;){const r=t[n];if(r&&"text"===r.type){let o=r.text||"",i=n+1;for(;i<t.length;){const e=t[i];if(!e||"text"!==e.type||!u(r,e))break;o+=e.text||"",i++}e.push({...r,text:o}),n=i}else e.push(r),n++}return e}(t)}for(const[t,n]of Object.entries(e))"children"!==t&&"object"==typeof n&&null!==n&&(e[t]=h(n));return e}function u(t,e){return t.format===e.format&&t.style===e.style&&t.mode===e.mode&&t.detail===e.detail}const m=async({editorId:t,editor:e,context:n})=>{try{const r=i.getCommentElement();if(!r)return;await new Promise(t=>setTimeout(t,500)),t||(t=a.getEditorId(e)??void 0);const o=d.getInstance({editorId:t,editor:e}),c=o.editorService.getSelectedText(e);if(!c)return;let s;const l=o.editorService.findOccurrenceIndex(e,c,null);if(!l)return;let g,h={};n&&"object"==typeof n&&(h={...h,...n}),h.textEditorConfig={text:c,occurrence:l,targetTextNodeId:s},t&&(h.textEditorConfig.editorId=t),r?.addManualComment({context:h,location:g})?.then(t=>{})}catch(t){i.catchError("Error adding lexical-velt-comments",t)}};const f=({editor:t,editorId:e,commentAnnotations:n})=>{try{if(t){if(e||(e=a.getEditorId(t)??void 0),!Array.isArray(n))return;n=JSON.parse(JSON.stringify(n));const r=n?.filter(t=>!!t.context?.textEditorConfig&&t.context?.textEditorConfig?.editorId===e)||[];d.getInstance({editorId:e,editor:t}).storeService.updateGlobalStore({editor:t,comments:r}),i.subscribeToSelectedAnnotationsMapSingleton()}}catch(t){i.catchError("Error highlighting lexical-velt-comments",t)}};exports.$createCommentNode=r,exports.$isCommentNode=o,exports.CommentNode=n,exports.addComment=m,exports.deserializeCleanState=function(t,n){try{const e=JSON.parse(n);t.setEditorState(t.parseEditorState(e))}catch(n){t.update(()=>{e.$getRoot().clear()})}},exports.exportCleanEditorContent=t=>{try{return l(t)}catch(n){return t.getEditorState().read(()=>{const t=e.$getRoot();return JSON.stringify({root:{children:[{children:[{detail:0,format:0,mode:"normal",style:"",text:t.getTextContent(),type:"text",version:1}],direction:"ltr",format:"",indent:0,type:"paragraph",version:1,textFormat:0,textStyle:""}],direction:"ltr",format:"",indent:0,type:"root",version:1}})})}},exports.highlightComments=function(t,e,n){try{f({editor:t,editorId:n,commentAnnotations:e})}catch(t){i.catchError("Error highlighting lexical-velt-comments",t)}},exports.renderComments=f,exports.triggerAddComment=async(t,e)=>{try{return m({editor:t,context:e?.context})}catch(t){i.catchError("Error triggering add comment",t)}};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
package/cjs/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/velt.ts","../../src/comment-node.ts","../../src/editor.ts","../../src/store.ts","../../src/plugin.ts","../../src/serializer.ts","../../src/index.ts"],"sourcesContent":["var _a;\nexport class VeltService {\n}\n_a = VeltService;\nVeltService.selectedCommentsMap = new Map();\nVeltService.subscribers = new Map();\nVeltService.isSubscribed = false;\n/* eslint-disable @typescript-eslint/no-explicit-any */\nVeltService.getCommentElement = () => {\n try {\n const velt = window.Velt;\n if (velt?.getCommentElement) {\n return velt.getCommentElement();\n }\n return null;\n }\n catch (error) {\n _a.catchError('Error getting comment element:', error);\n return null;\n }\n};\nVeltService.addManualComment = ({ context, location, }) => {\n try {\n const commentElement = _a.getCommentElement();\n if (!commentElement)\n return Promise.resolve(null);\n return commentElement.addManualComment({ context, location });\n }\n catch (error) {\n _a.catchError('Error adding manual comment:', error);\n return Promise.resolve(null);\n }\n};\nVeltService.updateContext = ({ annotationId, context, }) => {\n try {\n const commentElement = _a.getCommentElement();\n if (!commentElement)\n return Promise.resolve(null);\n return commentElement.updateContext(annotationId, context);\n }\n catch (error) {\n _a.catchError('Error updating context:', error);\n }\n};\nVeltService.subscribeToSelectedCommentsMap = (id, subscriber) => {\n try {\n _a.subscribeToSelectedAnnotationsMapSingleton();\n _a.subscribers.set(id, subscriber);\n }\n catch (error) {\n _a.catchError('Error subscribing to selected comments map:', error);\n }\n};\nVeltService.unsubscribeFromSelectedCommentsMap = (id) => {\n try {\n _a.subscribers.delete(id);\n }\n catch (error) {\n _a.catchError('Error unsubscribing from selected comments map:', error);\n }\n};\nVeltService.catchError = (message, otherProperties) => {\n try {\n const url = 'https://api.velt.dev/sa';\n let properties = {};\n if (otherProperties && typeof otherProperties === 'object') {\n properties = { ...properties, ...otherProperties };\n }\n if (message) {\n properties.message = message;\n }\n properties.sdkVersion = window.Velt?.version;\n const body = {\n type: 'track',\n data: {\n event: 'lexicalVeltCommentsError',\n properties: properties,\n },\n };\n // fetch(url, {\n // method: 'POST',\n // headers: {\n // 'Content-Type': 'application/json',\n // },\n // body: JSON.stringify(body),\n // });\n }\n catch (error) {\n // handle error here\n }\n};\nVeltService.subscribeToSelectedAnnotationsMapSingleton = () => {\n try {\n if (_a.isSubscribed) {\n return;\n }\n const commentElement = _a.getCommentElement();\n if (commentElement && typeof commentElement?.getSelectedComments === 'function') {\n commentElement?.getSelectedComments()?.subscribe((comments) => {\n const selectedCommentsMap = new Map();\n comments?.forEach((comment) => {\n if (comment?.annotationId) {\n selectedCommentsMap.set(comment?.annotationId, true);\n }\n });\n // Check if the maps are different\n const areMapsEqual = (map1, map2) => {\n if (map1.size !== map2.size)\n return false;\n for (const [key, value] of map1) {\n if (map2.get(key) !== value)\n return false;\n }\n return true;\n };\n // Skip update if maps are equal\n if (areMapsEqual(selectedCommentsMap, _a.selectedCommentsMap || new Map())) {\n return;\n }\n _a.updateSelectedCommentsMap(selectedCommentsMap);\n });\n _a.isSubscribed = true;\n }\n }\n catch (error) {\n return new Map();\n }\n};\nVeltService.updateSelectedCommentsMap = (selectedCommentsMap) => {\n try {\n _a.selectedCommentsMap = selectedCommentsMap;\n _a.subscribers.forEach((subscriber) => {\n if (typeof subscriber === 'function') {\n subscriber(_a.selectedCommentsMap);\n }\n });\n }\n catch (error) {\n _a.catchError('Error updating selected comments map:', error);\n }\n};\n","import { ElementNode } from 'lexical';\nexport class CommentNode extends ElementNode {\n static getType() {\n return 'comment';\n }\n static clone(node) {\n const cloned = new CommentNode(node.__annotationId, node.__multiThreadAnnotationId, node.__key);\n return cloned;\n }\n constructor(annotationId, multiThreadAnnotationId, key) {\n super(key);\n this.__annotationId = annotationId;\n this.__multiThreadAnnotationId = multiThreadAnnotationId;\n }\n createDOM(config) {\n const dom = document.createElement('velt-comment-text');\n if (this.__annotationId) {\n dom.setAttribute('annotation-id', this.__annotationId);\n }\n if (this.__multiThreadAnnotationId) {\n dom.setAttribute('multi-thread-annotation-id', this.__multiThreadAnnotationId);\n }\n return dom;\n }\n updateDOM(prevNode, dom, config) {\n return false;\n }\n static importJSON(serializedNode) {\n return $createCommentNode(serializedNode.annotationId, serializedNode.multiThreadAnnotationId);\n }\n exportJSON() {\n return {\n ...super.exportJSON(),\n annotationId: this.__annotationId,\n multiThreadAnnotationId: this.__multiThreadAnnotationId,\n type: 'comment',\n version: 1,\n };\n }\n isInline() {\n return true;\n }\n}\nexport function $createCommentNode(annotationId, multiThreadAnnotationId) {\n return new CommentNode(annotationId, multiThreadAnnotationId);\n}\nexport function $isCommentNode(node) {\n return node instanceof CommentNode;\n}\n","import { $createTextNode, $getRoot, $getSelection, $isElementNode, $isRangeSelection, $isTextNode } from 'lexical';\nimport { $createCommentNode, $isCommentNode } from './comment-node';\nimport { VeltService } from './velt';\nexport class EditorService {\n constructor(plugin) {\n this.plugin = plugin;\n }\n /**\n * Initialize the transaction listener (equivalent to TipTap's onTransaction)\n * Call this method when setting up the plugin\n */\n initializeTransactionListener(editor) {\n try {\n // Remove existing listener if any\n if (this.editorUpdateListenerRemover) {\n this.editorUpdateListenerRemover();\n }\n // Register update listener (equivalent to TipTap's onTransaction)\n this.editorUpdateListenerRemover = editor.registerUpdateListener(({ editorState, prevEditorState }) => {\n try {\n // Only process if the document content actually changed\n if (editorState === prevEditorState || !this.hasDocumentChanged(editorState, prevEditorState)) {\n return;\n }\n this.onTransaction(editor);\n }\n catch (error) {\n // do nothing\n }\n });\n }\n catch (err) {\n VeltService.catchError('Error initializing transaction listener:', err);\n }\n }\n /**\n * Clean up the transaction listener\n */\n destroyTransactionListener() {\n try {\n // Remove the listener\n if (this.editorUpdateListenerRemover) {\n this.editorUpdateListenerRemover();\n this.editorUpdateListenerRemover = undefined;\n }\n }\n catch (err) {\n VeltService.catchError('Error destroying transaction listener:', err);\n }\n }\n /**\n * Check if the document content has actually changed\n */\n hasDocumentChanged(currentState, prevState) {\n try {\n return currentState.read(() => {\n const currentText = $getRoot().getTextContent();\n return prevState.read(() => {\n const prevText = $getRoot().getTextContent();\n return currentText !== prevText;\n });\n });\n }\n catch (error) {\n return true; // Assume changed if we can't determine\n }\n }\n /**\n * Process editor changes\n */\n onTransaction(editor) {\n try {\n const changedAnnotationContent = new Map();\n // Phase 1: Collect all annotations in the document\n const annotationsToCheck = this.collectDocumentAnnotations(editor);\n // Phase 2: Process each annotation to check for changes\n for (const [annotationId, data] of Array.from(annotationsToCheck.entries())) {\n const changes = this.processAnnotationChanges(editor, data);\n if (changes) {\n changedAnnotationContent.set(annotationId, changes);\n }\n }\n // Phase 3: Apply updates for any annotations that changed\n if (changedAnnotationContent.size > 0) {\n const commentElement = VeltService.getCommentElement();\n if (!commentElement)\n return;\n this.updateVeltComments(commentElement, changedAnnotationContent, editor);\n }\n }\n catch (error) {\n VeltService.catchError('Error in onTransaction:', error);\n }\n }\n /**\n * Extract text from a CommentNode while preserving paragraph structure.\n * This method ensures that text extracted from existing comment nodes maintains\n * the same newline characters that were present during initial selection.\n *\n * @param commentNode - The CommentNode to extract text from\n * @returns Text content with preserved paragraph breaks (newlines)\n */\n getCommentNodeTextWithStructure(commentNode) {\n try {\n let text = '';\n const traverse = (node, depth = 0) => {\n if ($isTextNode(node)) {\n text += node.getTextContent();\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n const nodeType = node.getType();\n // Process all children first\n for (let i = 0; i < children.length; i++) {\n traverse(children[i], depth + 1);\n }\n // Add paragraph break after paragraph elements (except the last one)\n // This mirrors the logic in collectTextContent\n if (nodeType === 'paragraph' && depth >= 0) {\n const parent = node.getParent();\n if (parent && $isElementNode(parent)) {\n const siblings = parent.getChildren();\n const nodeIndex = siblings.indexOf(node);\n // Add newline if this is not the last paragraph\n if (nodeIndex < siblings.length - 1) {\n text += '\\n';\n }\n }\n }\n }\n };\n traverse(commentNode);\n return text;\n }\n catch (error) {\n // Fallback to original method if reconstruction fails\n return commentNode.getTextContent();\n }\n }\n /**\n * Collect all annotations present in the document for processing\n */\n collectDocumentAnnotations(editor) {\n try {\n const annotationsToCheck = new Map();\n // Capture 'this' context before entering the nested scope\n const self = this;\n editor.getEditorState().read(() => {\n const root = $getRoot();\n let currentPosition = 0;\n // Use arrow function to preserve 'this' context\n const traverse = (node) => {\n if ($isCommentNode(node)) {\n const annotationId = node.__annotationId;\n if (!annotationId)\n return;\n // Now we can access 'this' properly through 'self'\n const prevAnnotationData = self.plugin.storeService.annotationStore.get(annotationId);\n if (!prevAnnotationData)\n return;\n // Use consistent text collection that preserves paragraph structure\n const text = self.getCommentNodeTextWithStructure(node);\n const nodeSize = text.length;\n // Check if we've already processed this annotation\n const existingAnnotation = annotationsToCheck.get(annotationId);\n const nodeData = {\n node: { text, nodeSize },\n pos: currentPosition,\n };\n if (existingAnnotation) {\n existingAnnotation.nodes.push(nodeData);\n }\n else {\n annotationsToCheck.set(annotationId, {\n id: annotationId,\n multiThreadAnnotationId: node.__multiThreadAnnotationId,\n annotation: prevAnnotationData.annotation,\n nodes: [nodeData],\n originalText: prevAnnotationData.annotation.context?.textEditorConfig?.text || '',\n originalOccurrence: prevAnnotationData.annotation.context?.textEditorConfig?.occurrence || 1,\n targetTextNodeId: prevAnnotationData.annotation.context?.textEditorConfig?.targetTextNodeId || '',\n });\n }\n currentPosition += nodeSize;\n }\n else if ($isTextNode(node)) {\n currentPosition += node.getTextContent().length;\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n for (const child of children) {\n traverse(child);\n }\n }\n };\n traverse(root);\n });\n return annotationsToCheck;\n }\n catch (error) {\n VeltService.catchError('Error collecting document annotations:', error);\n return new Map();\n }\n }\n /**\n * Process annotation changes\n */\n processAnnotationChanges(editor, data) {\n try {\n // Input validation\n if (!editor || !data) {\n throw new Error('Invalid input: editor and data are required');\n }\n if (!data.originalText || !data.annotation) {\n return null;\n }\n if (!Array.isArray(data.nodes) || data.nodes.length === 0) {\n return null;\n }\n // Step 1: Detect content changes\n const { currentText, contentChanged } = this.detectContentChanges(data.nodes, data.originalText);\n // Step 2: Detect container changes and get updated search results\n const { targetTextNodeIdChanged, newTargetTextNodeId, searchResults } = this.detectContainerChanges(editor, {\n annotationId: data.id,\n currentText,\n targetTextNodeId: data.targetTextNodeId,\n nodes: data.nodes,\n });\n // Step 3: Calculate occurrence changes\n const currentOccurrence = this.calculateNewOccurrence(editor, {\n searchResults,\n nodes: data.nodes,\n contentChanged,\n currentText,\n targetTextNodeId: targetTextNodeIdChanged ? newTargetTextNodeId : data.targetTextNodeId,\n originalOccurrence: data.originalOccurrence,\n });\n const occurrenceChanged = currentOccurrence !== data.originalOccurrence;\n // Step 4: Create and return change object if any changes detected\n if (contentChanged || occurrenceChanged || targetTextNodeIdChanged) {\n return this.createAnnotationChange(data, {\n currentText,\n contentChanged,\n currentOccurrence,\n occurrenceChanged,\n targetTextNodeIdChanged,\n newTargetTextNodeId,\n });\n }\n return null;\n }\n catch (error) {\n VeltService.catchError('Error processing annotation changes:', error);\n return null;\n }\n }\n /**\n * Detect content changes while preserving paragraph structure.\n * When multiple CommentNodes represent different paragraphs of the same annotation,\n * we need to join them with newlines to match the original text format.\n */\n detectContentChanges(nodes, originalText) {\n const sortedNodes = [...nodes].sort((a, b) => a.pos - b.pos);\n // If we have multiple nodes (indicating multiple paragraphs), join with newlines\n // Otherwise, join normally\n const currentText = sortedNodes.length > 1 && originalText.includes('\\n')\n ? sortedNodes.map((n) => n.node.text || '').join('\\n')\n : sortedNodes.map((n) => n.node.text || '').join('');\n return {\n currentText,\n contentChanged: currentText !== originalText,\n };\n }\n /**\n * Detect container changes\n */\n detectContainerChanges(editor, params) {\n const { annotationId, currentText, targetTextNodeId, nodes } = params;\n let targetTextNodeIdChanged = false;\n let newTargetTextNodeId = targetTextNodeId;\n let searchResults = [];\n // First try to find text in the current container\n const containerChangeResult = this.processContainerChanges(editor, {\n annotationId,\n currentText,\n targetTextNodeId,\n nodes,\n });\n if (containerChangeResult) {\n targetTextNodeIdChanged = containerChangeResult.changed;\n newTargetTextNodeId = containerChangeResult.newId;\n searchResults = containerChangeResult.searchResults;\n }\n else {\n // No container change, search in current or document context\n searchResults = targetTextNodeId\n ? this.findTextInDomElement(editor, currentText, targetTextNodeId, undefined)\n : this.findTextInDocument(editor, currentText, undefined);\n }\n return {\n targetTextNodeIdChanged,\n newTargetTextNodeId,\n searchResults,\n };\n }\n /**\n * Process container changes\n */\n processContainerChanges(editor, params) {\n const { annotationId, currentText, targetTextNodeId } = params;\n if (!targetTextNodeId)\n return null;\n // Find the comment node with matching annotation ID\n let foundNodePosition = null;\n editor.getEditorState().read(() => {\n const root = $getRoot();\n let currentPos = 0;\n function traverse(node) {\n if ($isCommentNode(node) && node.__annotationId === annotationId) {\n foundNodePosition = currentPos;\n return;\n }\n if ($isTextNode(node)) {\n currentPos += node.getTextContent().length;\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n for (const child of children) {\n traverse(child);\n if (foundNodePosition !== null)\n return;\n }\n }\n }\n traverse(root);\n });\n if (foundNodePosition !== null) {\n // Find the corresponding DOM element and check its container\n const editorDOMElement = editor.getRootElement();\n if (!editorDOMElement)\n return null;\n // This is a simplified approach - in practice you'd want more precise DOM mapping\n const currentContainer = editorDOMElement.querySelector(`#${targetTextNodeId}`);\n if (currentContainer) {\n // Check if content is still within the same container\n const searchResults = this.findTextInDomElement(editor, currentText, targetTextNodeId, undefined);\n if (searchResults.length === 0) {\n // Content moved to a different container, try to find new container\n const newContainer = this.findNewContainer(editor, currentText);\n if (newContainer && newContainer.id !== targetTextNodeId) {\n const newSearchResults = this.findTextInDomElement(editor, currentText, newContainer.id, undefined);\n return {\n changed: true,\n newId: newContainer.id,\n searchResults: newSearchResults,\n };\n }\n }\n }\n }\n return null;\n }\n /**\n * Find new container for moved content\n */\n findNewContainer(editor, currentText) {\n const editorElement = editor.getRootElement();\n if (!editorElement)\n return null;\n // Find all elements with IDs that contain the text\n const elementsWithIds = editorElement.querySelectorAll('[id]');\n for (const element of Array.from(elementsWithIds)) {\n if (element.textContent?.includes(currentText)) {\n return element;\n }\n }\n return null;\n }\n /**\n * Calculate new occurrence\n */\n calculateNewOccurrence(editor, params) {\n if (params.searchResults.length === 0) {\n return params.originalOccurrence;\n }\n const firstNode = params.nodes[0];\n const lastNode = params.nodes[params.nodes.length - 1];\n const annotationRange = {\n from: firstNode.pos,\n to: lastNode.pos + (lastNode.node.nodeSize || 0),\n };\n for (let i = 0; i < params.searchResults.length; i++) {\n const result = params.searchResults[i];\n if ((result.start <= annotationRange.from && result.end >= annotationRange.from) ||\n (result.start <= annotationRange.to && result.end >= annotationRange.to) ||\n (annotationRange.from <= result.start && annotationRange.to >= result.end)) {\n return i + 1;\n }\n }\n return params.originalOccurrence;\n }\n /**\n * Create annotation change object\n */\n createAnnotationChange(data, changes) {\n const { currentText, contentChanged, currentOccurrence, occurrenceChanged, targetTextNodeIdChanged, newTargetTextNodeId, } = changes;\n return {\n annotationId: data.id,\n multiThreadAnnotationId: data.multiThreadAnnotationId,\n originalText: data.originalText,\n currentText: contentChanged ? currentText : data.originalText,\n originalOccurrence: data.originalOccurrence,\n currentOccurrence,\n originalTargetTextNodeId: data.targetTextNodeId,\n newTargetTextNodeId: targetTextNodeIdChanged ? newTargetTextNodeId : data.targetTextNodeId,\n annotation: data.annotation,\n contentChanged,\n occurrenceChanged,\n targetTextNodeIdChanged,\n };\n }\n /**\n * Update Velt comments\n */\n async updateVeltComments(commentElement, changes, editor) {\n try {\n for (const [annotationId, changeData] of Array.from(changes.entries())) {\n try {\n if (!changeData.annotation.context?.textEditorConfig)\n continue;\n const textEditorConfig = JSON.parse(JSON.stringify(changeData.annotation.context.textEditorConfig));\n if (changeData.contentChanged) {\n textEditorConfig.text = changeData.currentText;\n }\n if (changeData.occurrenceChanged) {\n textEditorConfig.occurrence = changeData.currentOccurrence;\n }\n if (changeData.targetTextNodeIdChanged) {\n textEditorConfig.targetTextNodeId = changeData.newTargetTextNodeId;\n }\n const context = {\n ...changeData.annotation.context,\n textEditorConfig,\n };\n // Remove data from store\n this.plugin.storeService.annotationStore.remove(annotationId);\n this.removeVeltCommentFromEditor(editor, annotationId);\n // delay 100ms\n await new Promise(resolve => setTimeout(resolve, 100));\n VeltService.updateContext({ annotationId, context });\n }\n catch (err) {\n VeltService.catchError('Error updating individual Velt comment:', err);\n }\n }\n }\n catch (err) {\n VeltService.catchError('Error updating Velt comments:', err);\n }\n }\n getSelectedText(editor) {\n return editor.getEditorState().read(() => {\n const selection = $getSelection();\n return $isRangeSelection(selection) ? selection.getTextContent() : '';\n });\n }\n /**\n * Find occurrence index of selected text in Lexical editor.\n * This method determines which occurrence of a text pattern the current selection represents,\n * which is crucial for multi-paragraph text selections that span across different paragraphs.\n *\n * @param editor - The Lexical editor instance\n * @param selectedText - The text that is currently selected (may include newlines for multi-paragraph selections)\n * @param targetContainer - Optional container element to limit search scope\n * @returns The 1-indexed occurrence number of the selected text\n */\n findOccurrenceIndex(editor, selectedText, targetContainer) {\n try {\n if (!selectedText.trim()) {\n return 1;\n }\n let matches = [];\n let selectionStart = 0;\n let selectionEnd = 0;\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n if ($isRangeSelection(selection)) {\n // Get current selection range in terms of text offset (including paragraph breaks)\n const range = this.getSelectionTextRange(editor, selection);\n selectionStart = range.start;\n selectionEnd = range.end;\n // Find all matches in the specified scope\n matches = targetContainer && targetContainer.id\n ? this.findTextInContainer(editor, selectedText, targetContainer.id)\n : this.findTextInEditor(editor, selectedText);\n }\n });\n // Find which occurrence matches our current selection position\n for (let i = 0; i < matches.length; i++) {\n if (matches[i].start === selectionStart && matches[i].end === selectionEnd) {\n return i + 1; // Return 1-indexed occurrence\n }\n }\n return 1;\n }\n catch (error) {\n VeltService.catchError('Error finding occurrence index:', error);\n return 1;\n }\n }\n /**\n * Get the text range of current selection, accounting for paragraph breaks.\n * This method maps Lexical selection positions to text offsets in the combined text\n * representation that includes newline characters between paragraphs.\n *\n * @param editor - The Lexical editor instance\n * @param selection - The current range selection\n * @returns Object with start and end positions in the combined text\n */\n getSelectionTextRange(editor, selection) {\n const root = $getRoot();\n const { nodeMap } = this.collectTextContent(root);\n // Get the anchor and focus nodes from the selection\n const anchorNode = selection.anchor.getNode();\n const focusNode = selection.focus.getNode();\n const anchorOffset = selection.anchor.offset;\n const focusOffset = selection.focus.offset;\n // Map node positions to text offsets in the combined text\n let anchorTextPos = 0;\n let focusTextPos = 0;\n for (const item of nodeMap) {\n // Skip paragraph breaks for node mapping\n if (item.isParagraphBreak || !item.node) {\n continue;\n }\n const nodeKey = item.node.getKey();\n if (nodeKey === anchorNode.getKey()) {\n anchorTextPos = item.start + anchorOffset;\n }\n if (nodeKey === focusNode.getKey()) {\n focusTextPos = item.start + focusOffset;\n }\n }\n // Return ordered range (start should be less than end)\n return {\n start: Math.min(anchorTextPos, focusTextPos),\n end: Math.max(anchorTextPos, focusTextPos)\n };\n }\n /**\n * Collect all text content including paragraph breaks.\n * This method creates a combined text representation of the entire document,\n * inserting newline characters between paragraphs to maintain text structure\n * for accurate multi-paragraph text matching.\n *\n * @param root - The root Lexical node to traverse\n * @returns Object containing:\n * - combinedText: Complete text with newlines between paragraphs\n * - nodeMap: Array mapping each text node and paragraph break to its position\n */\n collectTextContent(root) {\n try {\n const nodeMap = [];\n let combinedText = '';\n let currentOffset = 0;\n const traverse = (node, depth = 0) => {\n if ($isTextNode(node)) {\n const text = node.getTextContent();\n const startOffset = currentOffset;\n const endOffset = currentOffset + text.length;\n // Map this text node to its position in combined text\n nodeMap.push({\n node,\n start: startOffset,\n end: endOffset\n });\n combinedText += text;\n currentOffset += text.length;\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n const nodeType = node.getType();\n // Process all children first\n for (let i = 0; i < children.length; i++) {\n traverse(children[i], depth + 1);\n }\n // Add paragraph break after paragraph elements (except the last one)\n if (nodeType === 'paragraph' && depth === 1) {\n const parent = node.getParent();\n if (parent && $isElementNode(parent)) {\n const siblings = parent.getChildren();\n const nodeIndex = siblings.indexOf(node);\n // Add newline if this is not the last paragraph\n if (nodeIndex < siblings.length - 1) {\n const startOffset = currentOffset;\n const endOffset = currentOffset + 1;\n // Map the paragraph break to its position\n nodeMap.push({\n node: null,\n start: startOffset,\n end: endOffset,\n isParagraphBreak: true\n });\n combinedText += '\\n';\n currentOffset += 1;\n }\n }\n }\n }\n };\n traverse(root);\n return { combinedText, nodeMap };\n }\n catch (error) {\n VeltService.catchError('Error collecting text content:', error);\n return { combinedText: '', nodeMap: [] };\n }\n }\n /**\n * Find all text occurrences in the entire Lexical editor.\n * This method supports multi-paragraph text search by using the combined text\n * representation that includes newline characters between paragraphs.\n *\n * @param editor - The Lexical editor instance\n * @param searchText - The text to search for (may include newlines for multi-paragraph searches)\n * @returns Array of TextMatch objects with start and end positions\n */\n findTextInEditor(editor, searchText) {\n try {\n const matches = [];\n editor.getEditorState().read(() => {\n const root = $getRoot();\n const { combinedText } = this.collectTextContent(root);\n // Use KMP search on the combined text (which includes newlines)\n const positions = this.kmpSearch(combinedText, searchText);\n // Convert string positions to TextMatch objects\n for (const pos of positions) {\n matches.push({\n start: pos,\n end: pos + searchText.length\n });\n }\n });\n return matches;\n }\n catch (error) {\n VeltService.catchError('Error finding text in editor:', error);\n return [];\n }\n }\n /**\n * Find text occurrences within a specific DOM container (Updated to handle paragraph breaks)\n */\n findTextInContainer(editor, searchText, containerId) {\n try {\n const matches = [];\n const containerElement = document.getElementById(containerId);\n if (!containerElement) {\n return matches;\n }\n editor.getEditorState().read(() => {\n const root = $getRoot();\n const { combinedText, nodeMap } = this.collectTextContent(root);\n // Filter content that belongs to the container\n const containerContent = this.getContainerTextContent(containerElement, editor, nodeMap, combinedText);\n if (!containerContent) {\n return;\n }\n const positions = this.kmpSearch(containerContent.text, searchText);\n // Convert positions to global text offsets\n for (const pos of positions) {\n matches.push({\n start: containerContent.startOffset + pos,\n end: containerContent.startOffset + pos + searchText.length\n });\n }\n });\n return matches;\n }\n catch (error) {\n VeltService.catchError('Error finding text in container:', error);\n return [];\n }\n }\n /**\n * Get text content for a specific container\n */\n getContainerTextContent(containerElement, editor, nodeMap, combinedText) {\n try {\n let containerStartOffset = -1;\n let containerEndOffset = -1;\n // Find the range of text that belongs to this container\n for (let i = 0; i < nodeMap.length; i++) {\n const item = nodeMap[i];\n if (item.isParagraphBreak) {\n continue; // Skip paragraph breaks for DOM mapping\n }\n if (item.node) {\n try {\n const nodeKey = item.node.getKey();\n const nodeDOMElement = editor.getElementByKey(nodeKey);\n if (nodeDOMElement && containerElement.contains(nodeDOMElement)) {\n if (containerStartOffset === -1) {\n containerStartOffset = item.start;\n }\n containerEndOffset = item.end;\n }\n }\n catch (error) {\n // Skip nodes that can't be mapped to DOM\n continue;\n }\n }\n }\n if (containerStartOffset === -1 || containerEndOffset === -1) {\n return null;\n }\n const containerText = combinedText.substring(containerStartOffset, containerEndOffset);\n return {\n text: containerText,\n startOffset: containerStartOffset\n };\n }\n catch (error) {\n return null;\n }\n }\n /**\n * Filter text nodes that are within a specific DOM container\n */\n filterNodesInContainer(textNodes, containerElement, editor) {\n try {\n const containerNodes = [];\n for (const textNodeData of textNodes) {\n try {\n // Get DOM element for this Lexical node\n const nodeKey = textNodeData.node.getKey();\n const nodeDOMElement = editor.getElementByKey(nodeKey);\n if (nodeDOMElement && containerElement.contains(nodeDOMElement)) {\n containerNodes.push(textNodeData);\n }\n }\n catch (error) {\n // Skip nodes that can't be mapped to DOM\n continue;\n }\n }\n return containerNodes;\n }\n catch (error) {\n return [];\n }\n }\n /**\n * Collect all text nodes with their cumulative text offsets (helper method)\n */\n collectTextNodes(root) {\n try {\n const textNodes = [];\n let currentTextOffset = 0;\n const traverse = (node) => {\n if ($isTextNode(node)) {\n const text = node.getTextContent();\n textNodes.push({\n node,\n text,\n textOffset: currentTextOffset\n });\n currentTextOffset += text.length;\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n for (const child of children) {\n traverse(child);\n }\n }\n };\n traverse(root);\n return textNodes;\n }\n catch (error) {\n return [];\n }\n }\n /**\n * Get text nodes within a specific character range (Updated to handle paragraph breaks)\n */\n getTextNodesInRange(root, fromPos, toPos, excludeAnnotationId) {\n try {\n const textNodes = [];\n const { combinedText, nodeMap } = this.collectTextContent(root);\n // Find all text nodes that overlap with the target range\n for (const item of nodeMap) {\n // Skip paragraph breaks and non-text nodes\n if (item.isParagraphBreak || !item.node) {\n continue;\n }\n // Skip comment nodes with the same annotation ID\n const parent = item.node.getParent();\n if ($isCommentNode(parent) && excludeAnnotationId && parent.__annotationId === excludeAnnotationId) {\n continue;\n }\n // Check if this node overlaps with our target range\n if (item.end > fromPos && item.start < toPos) {\n const startOffset = Math.max(0, fromPos - item.start);\n const endOffset = Math.min(item.node.getTextContent().length, toPos - item.start);\n const isPartial = startOffset > 0 || endOffset < item.node.getTextContent().length;\n textNodes.push({\n node: item.node,\n startOffset,\n endOffset,\n isPartial\n });\n }\n }\n return textNodes;\n }\n catch (error) {\n VeltService.catchError('Error getting text nodes in range:', error);\n return [];\n }\n }\n /**\n * Check if a text range is already wrapped (Updated to handle paragraph breaks)\n */\n isRangeAlreadyWrapped(root, fromPos, toPos, annotationId) {\n try {\n let currentPosition = 0;\n let foundWrapping = false;\n const traverse = (node) => {\n if ($isCommentNode(node)) {\n if (node.__annotationId === annotationId) {\n const text = node.getTextContent();\n const nodeStart = currentPosition;\n const nodeEnd = currentPosition + text.length;\n // Check if this comment node covers our target range\n if (nodeStart <= fromPos && nodeEnd >= toPos) {\n foundWrapping = true;\n return true;\n }\n }\n const text = node.getTextContent();\n currentPosition += text.length;\n }\n else if ($isTextNode(node)) {\n const text = node.getTextContent();\n currentPosition += text.length;\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n for (const child of children) {\n if (traverse(child)) {\n return true;\n }\n }\n // Add paragraph break length if this is a paragraph (except last one)\n const nodeType = node.getType();\n if (nodeType === 'paragraph') {\n const parent = node.getParent();\n if (parent && $isElementNode(parent)) {\n const siblings = parent.getChildren();\n const nodeIndex = siblings.indexOf(node);\n if (nodeIndex < siblings.length - 1) {\n currentPosition += 1; // Add newline length\n }\n }\n }\n }\n return false;\n };\n traverse(root);\n return foundWrapping;\n }\n catch (error) {\n // If there's an error, assume it's wrapped to avoid breaking the flow\n return true;\n }\n }\n /**\n * Collect text nodes within a specific range\n */\n collectTextNodesInRange(root, range) {\n try {\n const textNodes = [];\n let currentOffset = 0;\n const traverse = (node) => {\n const nodeStart = currentOffset;\n if ($isTextNode(node)) {\n const text = node.getTextContent();\n const nodeEnd = currentOffset + text.length;\n // Check if node overlaps with target range\n if (nodeEnd >= range.start && nodeStart <= range.end) {\n textNodes.push({\n node,\n text,\n start: currentOffset,\n end: nodeEnd\n });\n }\n currentOffset = nodeEnd;\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n for (const child of children) {\n traverse(child);\n }\n }\n };\n traverse(root);\n return textNodes;\n }\n catch (error) {\n return [];\n }\n }\n /**\n * Get the text range for a specific DOM container\n */\n getContainerRange(editor, containerElement) {\n try {\n // Find Lexical nodes that correspond to the container\n // This is a simplified approach - you might need more sophisticated mapping\n const editorElement = editor.getRootElement();\n if (!editorElement || !editorElement.contains(containerElement)) {\n return null;\n }\n // Calculate approximate range based on DOM position\n // In practice, you'd want a more precise mapping between DOM and Lexical positions\n const containerText = containerElement.textContent || '';\n const editorText = editorElement.textContent || '';\n const startIndex = editorText.indexOf(containerText);\n if (startIndex === -1)\n return null;\n return {\n start: startIndex,\n end: startIndex + containerText.length\n };\n }\n catch (error) {\n VeltService.catchError('Error getting container range:', error);\n return null;\n }\n }\n /**\n * KMP Search implementation\n */\n kmpSearch(text, pattern, startPos = 0, maxOccurrences) {\n try {\n const positions = [];\n if (!pattern || !text || pattern.length > text.length)\n return positions;\n const lps = this.computeKMPTable(pattern);\n let i = 0;\n let j = 0;\n while (i < text.length) {\n if (pattern[j] === text[i]) {\n i++;\n j++;\n }\n if (j === pattern.length) {\n positions.push(startPos + i - j);\n j = lps[j - 1];\n if (maxOccurrences && positions.length >= maxOccurrences) {\n break;\n }\n }\n else if (i < text.length && pattern[j] !== text[i]) {\n if (j !== 0) {\n j = lps[j - 1];\n }\n else {\n i++;\n }\n }\n }\n return positions;\n }\n catch (error) {\n return [];\n }\n }\n /**\n * Compute KMP failure function\n */\n computeKMPTable(pattern) {\n try {\n const lps = new Array(pattern.length).fill(0);\n let len = 0;\n let i = 1;\n while (i < pattern.length) {\n if (pattern[i] === pattern[len]) {\n len++;\n lps[i] = len;\n i++;\n }\n else {\n if (len !== 0) {\n len = lps[len - 1];\n }\n else {\n lps[i] = 0;\n i++;\n }\n }\n }\n return lps;\n }\n catch (error) {\n return [];\n }\n }\n // Helper to find parent container with ID\n findParentContainerWithId(selection, editor) {\n try {\n const anchorNode = selection.anchor.getNode();\n const dom = editor.getElementByKey(anchorNode.getKey());\n if (!dom)\n return null;\n let current = dom;\n while (current && current !== document.body) {\n if (current.id) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n }\n catch (error) {\n return null;\n }\n }\n /**\n * Highlights text in the editor with a Velt comment annotation.\n * This method supports multi-paragraph text highlighting by preserving paragraph structure\n * and creating separate comment nodes for each paragraph when necessary.\n *\n * @param editor - The Lexical editor instance\n * @param textToFind - The text to highlight (may include newlines for multi-paragraph selections)\n * @param commentOptions - Configuration options for the comment annotation\n */\n highlightTextWithVeltComment(editor, textToFind, commentOptions) {\n try {\n const { targetTextNodeId } = commentOptions;\n const desiredOccurrence = commentOptions?.occurrence || 1;\n // Check if newTextEditorConfig is different from stored annotation textEditorConfig\n if (commentOptions.annotationId) {\n const storedData = this.plugin.storeService.annotationStore.get(commentOptions.annotationId);\n if (storedData) {\n const storedConfig = storedData.annotation.context?.textEditorConfig;\n const newConfig = commentOptions.originalAnnotation?.context?.textEditorConfig;\n if (storedConfig &&\n newConfig &&\n (storedConfig.text !== newConfig.text ||\n storedConfig.occurrence !== newConfig.occurrence ||\n storedConfig.targetTextNodeId !== newConfig.targetTextNodeId)) {\n this.removeVeltCommentFromEditor(editor, commentOptions.annotationId);\n }\n }\n }\n if (!textToFind || textToFind.length === 0) {\n return;\n }\n // Validate location if targetTextNodeId is provided\n if (targetTextNodeId) {\n const domNode = document.getElementById(targetTextNodeId);\n if (domNode) {\n const locationId = domNode\n .closest(`[data-velt-location-id]`) // Adjust this attribute as per your Constants\n ?.getAttribute('data-velt-location-id');\n if (locationId !== commentOptions.originalAnnotation?.location?.id) {\n return;\n }\n }\n }\n // Find text matches in the appropriate scope\n let matches = [];\n if (targetTextNodeId) {\n matches = this.findTextInDomElement(editor, textToFind, targetTextNodeId, desiredOccurrence);\n }\n else {\n matches = this.findTextInDocument(editor, textToFind, desiredOccurrence);\n }\n if (matches.length === 0) {\n return;\n }\n const occurrence = Math.min(desiredOccurrence, matches.length);\n const matchToConsider = matches[occurrence - 1];\n if (matchToConsider && commentOptions.annotationId) {\n // Check if this range is already wrapped with the same annotation ID\n const isAlreadyWrapped = editor.getEditorState().read(() => {\n const root = $getRoot();\n return this.isRangeAlreadyWrapped(root, matchToConsider.start, matchToConsider.end, commentOptions.annotationId);\n });\n // If already wrapped with the same annotation ID, skip wrapping\n if (isAlreadyWrapped) {\n return;\n }\n // Store annotation data\n this.plugin.storeService.annotationStore.set(commentOptions.annotationId, {\n annotation: commentOptions.originalAnnotation || {\n annotationId: commentOptions.annotationId,\n multiThreadAnnotationId: commentOptions.multiThreadAnnotationId,\n text: textToFind,\n },\n pluginReference: {\n node: document.createElement('velt-comment-text'),\n position: { from: matchToConsider.start, to: matchToConsider.end },\n },\n });\n // Apply highlighting in Lexical with multi-paragraph support\n this.setVeltComment(editor, commentOptions.annotationId, commentOptions.multiThreadAnnotationId, matchToConsider.start, matchToConsider.end);\n }\n }\n catch (error) {\n VeltService.catchError('Error highlighting text with Velt comment:', error);\n }\n }\n /**\n * Find text within a specific DOM element\n */\n findTextInDomElement(editor, text, domElementId, desiredOccurrence) {\n try {\n const matches = [];\n const domNode = document.getElementById(domElementId);\n if (!domNode) {\n return matches;\n }\n editor.getEditorState().read(() => {\n const root = $getRoot();\n const containerTextNodes = this.filterNodesInContainer(this.collectTextNodes(root), domNode, editor);\n if (containerTextNodes.length === 0) {\n return;\n }\n const containerStartOffset = containerTextNodes[0].textOffset;\n const combinedText = containerTextNodes.map(node => node.text).join('');\n const positions = this.kmpSearch(combinedText, text, 0, desiredOccurrence);\n for (const pos of positions) {\n matches.push({\n start: containerStartOffset + pos,\n end: containerStartOffset + pos + text.length\n });\n }\n });\n return matches;\n }\n catch (error) {\n return [];\n }\n }\n /**\n * Find text in the entire document with support for multi-paragraph searches.\n * This method is used by the highlighting system to locate text that needs to be wrapped\n * with comment annotations, including text that spans across multiple paragraphs.\n *\n * @param editor - The Lexical editor instance\n * @param text - The text to search for (may include newlines for multi-paragraph searches)\n * @param desiredOccurrence - Optional limit on the number of occurrences to find\n * @returns Array of TextMatch objects with start and end positions\n */\n findTextInDocument(editor, text, desiredOccurrence) {\n try {\n const matches = [];\n editor.getEditorState().read(() => {\n const root = $getRoot();\n const { combinedText } = this.collectTextContent(root);\n // Use KMP search on the combined text (which includes newlines)\n const positions = this.kmpSearch(combinedText, text, 0, desiredOccurrence);\n // Convert string positions to TextMatch objects\n for (const pos of positions) {\n matches.push({\n start: pos,\n end: pos + text.length\n });\n }\n });\n return matches;\n }\n catch (error) {\n VeltService.catchError('Error finding text in document:', error);\n return [];\n }\n }\n /**\n * Creates a Velt comment highlight at the specified range.\n * This method intelligently handles different scenarios including single text nodes,\n * partial text nodes, and multi-paragraph selections while preserving document structure.\n *\n * @param editor - The Lexical editor instance\n * @param annotationId - The annotation ID for the comment\n * @param multiThreadAnnotationId - Optional multi-thread annotation ID\n * @param fromPos - Start position in the combined text representation\n * @param toPos - End position in the combined text representation\n */\n setVeltComment(editor, annotationId, multiThreadAnnotationId, fromPos, toPos) {\n try {\n editor.update(() => {\n const root = $getRoot();\n // Clear any existing selection to prevent selection anchor issues during node manipulation\n root.selectStart();\n // Get text nodes in the specified range, excluding already wrapped nodes\n const textNodesToWrap = this.getTextNodesInRange(root, fromPos, toPos, annotationId);\n if (textNodesToWrap.length === 0) {\n return;\n }\n // Create comment node with annotation ID\n const commentNode = $createCommentNode(annotationId, multiThreadAnnotationId);\n // Handle different scenarios based on how many text nodes are involved\n if (textNodesToWrap.length === 1) {\n const { node, startOffset, endOffset, isPartial } = textNodesToWrap[0];\n if (isPartial) {\n // Split the text node and wrap only the selected part\n this.wrapPartialTextNode(node, startOffset, endOffset, commentNode);\n }\n else {\n // Wrap the entire text node\n this.wrapEntireTextNode(node, commentNode);\n }\n }\n else {\n // Multiple text nodes - preserve paragraph structure and formatting\n this.wrapMultipleTextNodesWithFormatting(textNodesToWrap, commentNode);\n }\n });\n }\n catch (error) {\n VeltService.catchError('Error setting Velt comment:', error);\n }\n }\n /**\n * Wrap a partial text node (when selection is within the node) - PRESERVING FORMATTING\n */\n wrapPartialTextNode(textNode, startOffset, endOffset, commentNode) {\n try {\n const writableNode = textNode.getWritable();\n const fullText = writableNode.getTextContent();\n // Split the text into three parts: before, selected, after\n const beforeText = fullText.substring(0, startOffset);\n const selectedText = fullText.substring(startOffset, endOffset);\n const afterText = fullText.substring(endOffset);\n // Create the selected portion as a text node with the same formatting as the original\n const selectedTextNode = $createTextNode(selectedText);\n // Copy formatting from original node to new node\n selectedTextNode.setFormat(writableNode.getFormat());\n selectedTextNode.setStyle(writableNode.getStyle());\n commentNode.append(selectedTextNode);\n // Handle the before and after parts\n if (beforeText) {\n const beforeNode = $createTextNode(beforeText);\n beforeNode.setFormat(writableNode.getFormat());\n beforeNode.setStyle(writableNode.getStyle());\n writableNode.insertBefore(beforeNode);\n }\n writableNode.insertBefore(commentNode);\n if (afterText) {\n const afterNode = $createTextNode(afterText);\n afterNode.setFormat(writableNode.getFormat());\n afterNode.setStyle(writableNode.getStyle());\n writableNode.insertBefore(afterNode);\n }\n // Remove the original node\n writableNode.remove();\n }\n catch (error) {\n // do nothing\n }\n }\n /**\n * Wrap an entire text node - PRESERVING FORMATTING\n */\n wrapEntireTextNode(textNode, commentNode) {\n try {\n const writableNode = textNode.getWritable();\n // Move the original node into the comment node (preserving all formatting)\n commentNode.append(writableNode);\n // Get the parent and replace the original node position with the comment node\n const parent = writableNode.getParent();\n if (parent) {\n const parentWritable = parent.getWritable();\n const nodeIndex = writableNode.getIndexWithinParent();\n parentWritable.splice(nodeIndex, 1, [commentNode]);\n }\n }\n catch (error) {\n // do nothing\n }\n }\n /**\n * Wrap multiple text nodes while preserving formatting and paragraph structure.\n * This method groups text nodes by their paragraph parent and creates separate\n * comment nodes for each paragraph to maintain document structure integrity.\n *\n * @param textNodesToWrap - Array of text nodes with their offset information\n * @param commentNode - The base comment node to use (additional nodes will be created for other paragraphs)\n */\n wrapMultipleTextNodesWithFormatting(textNodesToWrap, commentNode) {\n try {\n // Group nodes by their paragraph parent to maintain paragraph structure\n const nodesByParagraph = new Map();\n for (const nodeData of textNodesToWrap) {\n const paragraphParent = this.findParagraphParent(nodeData.node);\n const paragraphKey = paragraphParent ? paragraphParent.getKey() : 'no-paragraph';\n if (!nodesByParagraph.has(paragraphKey)) {\n nodesByParagraph.set(paragraphKey, []);\n }\n nodesByParagraph.get(paragraphKey).push(nodeData);\n }\n // Create separate comment nodes for each paragraph\n let isFirstParagraph = true;\n for (const [, nodesInParagraph] of nodesByParagraph.entries()) {\n // Create a comment node for this paragraph (reuse the first one, create new ones for others)\n const paragraphCommentNode = isFirstParagraph\n ? commentNode\n : $createCommentNode(commentNode.__annotationId, commentNode.__multiThreadAnnotationId);\n // Process nodes within this paragraph\n if (nodesInParagraph.length === 1) {\n const nodeData = nodesInParagraph[0];\n const { node, startOffset, endOffset, isPartial } = nodeData;\n if (isPartial) {\n this.wrapPartialTextNode(node, startOffset, endOffset, paragraphCommentNode);\n }\n else {\n this.wrapEntireTextNode(node, paragraphCommentNode);\n }\n }\n else {\n // Multiple nodes in same paragraph - handle them sequentially\n this.wrapMultipleNodesInSameParagraph(nodesInParagraph, paragraphCommentNode);\n }\n isFirstParagraph = false;\n }\n }\n catch (error) {\n VeltService.catchError('Error in wrapMultipleTextNodesWithFormatting:', error);\n }\n }\n /**\n * Find the paragraph parent of a text node.\n * Traverses up the node hierarchy to find the paragraph element that contains this text node.\n *\n * @param node - The text node to find the paragraph parent for\n * @returns The paragraph node or null if not found\n */\n findParagraphParent(node) {\n let current = node.getParent();\n while (current) {\n if ($isElementNode(current) && current.getType() === 'paragraph') {\n return current;\n }\n current = current.getParent();\n }\n return null;\n }\n /**\n * Wrap multiple text nodes within the same paragraph.\n * This method handles complex scenarios where multiple text nodes need to be wrapped\n * while maintaining their original formatting and order within the paragraph.\n *\n * @param nodesInParagraph - Array of text nodes within the same paragraph\n * @param commentNode - The comment node to wrap the text nodes with\n */\n wrapMultipleNodesInSameParagraph(nodesInParagraph, commentNode) {\n try {\n // Sort nodes by their position in the paragraph\n const sortedNodes = [...nodesInParagraph].sort((a, b) => {\n const aIndex = a.node.getIndexWithinParent();\n const bIndex = b.node.getIndexWithinParent();\n return aIndex - bIndex;\n });\n const firstNodeData = sortedNodes[0];\n const lastNodeData = sortedNodes[sortedNodes.length - 1];\n // Handle first node\n const firstNode = firstNodeData.node.getWritable();\n const parent = firstNode.getParent();\n if (!parent)\n return;\n const parentWritable = parent.getWritable();\n let insertionIndex = firstNode.getIndexWithinParent();\n // Process first node\n if (firstNodeData.isPartial && firstNodeData.startOffset > 0) {\n // Split the first node - keep text before selection separate\n const beforeText = firstNodeData.node.getTextContent().substring(0, firstNodeData.startOffset);\n const selectedText = firstNodeData.node.getTextContent().substring(firstNodeData.startOffset);\n const beforeNode = $createTextNode(beforeText);\n beforeNode.setFormat(firstNode.getFormat());\n beforeNode.setStyle(firstNode.getStyle());\n const selectedPartNode = $createTextNode(selectedText);\n selectedPartNode.setFormat(firstNode.getFormat());\n selectedPartNode.setStyle(firstNode.getStyle());\n commentNode.append(selectedPartNode);\n // Replace original node with before node and comment node\n parentWritable.splice(insertionIndex, 1, [beforeNode, commentNode]);\n }\n else {\n // Replace entire first node with comment node (move content into comment)\n commentNode.append(firstNode);\n parentWritable.splice(insertionIndex, 1, [commentNode]);\n }\n // Process middle nodes (if any) - move them into the comment node\n for (let i = 1; i < sortedNodes.length - 1; i++) {\n const nodeData = sortedNodes[i];\n const writableNode = nodeData.node.getWritable();\n // Move the entire middle node into comment node (preserves formatting)\n commentNode.append(writableNode);\n // Node is automatically removed from its original parent when moved\n }\n // Process last node (if different from first)\n if (sortedNodes.length > 1) {\n const lastNode = lastNodeData.node.getWritable();\n if (lastNodeData.isPartial && lastNodeData.endOffset < lastNodeData.node.getTextContent().length) {\n // Split the last node - keep text after selection separate\n const selectedText = lastNodeData.node.getTextContent().substring(0, lastNodeData.endOffset);\n const afterText = lastNodeData.node.getTextContent().substring(lastNodeData.endOffset);\n const selectedPartNode = $createTextNode(selectedText);\n selectedPartNode.setFormat(lastNode.getFormat());\n selectedPartNode.setStyle(lastNode.getStyle());\n const afterNode = $createTextNode(afterText);\n afterNode.setFormat(lastNode.getFormat());\n afterNode.setStyle(lastNode.getStyle());\n commentNode.append(selectedPartNode);\n // Replace the last node with just the remaining text\n lastNode.replace(afterNode);\n }\n else {\n // Move entire last node into comment\n commentNode.append(lastNode);\n // Node is automatically removed from its original parent when moved\n }\n }\n }\n catch (error) {\n VeltService.catchError('Error in wrapMultipleNodesInSameParagraph:', error);\n }\n }\n /**\n * Removes a Velt comment from the Lexical document\n * @param editor - The Lexical editor instance\n * @param annotationId - The ID of the annotation to remove\n * @returns boolean - True if the annotation was successfully removed, false otherwise\n * @throws Error if the stored data is invalid\n */\n removeVeltCommentFromEditor(editor, annotationId) {\n try {\n // Validate input\n if (!editor || !annotationId) {\n throw new Error('Invalid input: editor and annotationId are required');\n }\n // Track if we found and removed any comment nodes\n let nodesRemoved = false;\n // Use Lexical's update mechanism for atomic changes (equivalent to TipTap's editor.chain())\n editor.update(() => {\n const root = $getRoot();\n const commentNodesToRemove = [];\n // Traverse all nodes to find CommentNodes (equivalent to TipTap's doc.descendants)\n function traverse(node) {\n if ($isCommentNode(node)) {\n // Check if this comment node has the matching annotation ID\n if (node.__annotationId === annotationId) {\n commentNodesToRemove.push(node);\n }\n }\n else if ($isElementNode(node)) {\n const children = node.getChildren();\n for (const child of children) {\n traverse(child);\n }\n }\n }\n traverse(root);\n // Remove the found CommentNodes (equivalent to TipTap's tr.removeMark)\n for (const commentNode of commentNodesToRemove) {\n try {\n const writableNode = commentNode.getWritable();\n // Get all child nodes from the comment node\n const children = writableNode.getChildren();\n if (children.length > 0) {\n // Replace comment node with its children (preserving content and formatting)\n const firstChild = children[0];\n // Replace the comment node with the first child\n writableNode.replace(firstChild);\n // Insert remaining children after the first one\n let insertAfter = firstChild;\n for (let i = 1; i < children.length; i++) {\n insertAfter.insertAfter(children[i]);\n insertAfter = children[i];\n }\n }\n else {\n // If no children, check if there's text content\n const textContent = writableNode.getTextContent();\n if (textContent) {\n // Create a text node with the content\n const textNode = $createTextNode(textContent);\n writableNode.replace(textNode);\n }\n else {\n // If no content, just remove the node\n writableNode.remove();\n }\n }\n nodesRemoved = true;\n }\n catch (nodeError) {\n VeltService.catchError('Error removing individual comment node:', nodeError);\n // Continue with other nodes even if one fails\n }\n }\n });\n // Clean up from annotation store if nodes were removed\n if (nodesRemoved) {\n this.plugin.storeService.annotationStore.remove(annotationId);\n }\n return nodesRemoved;\n }\n catch (error) {\n // VeltService.catchError('Error removing Velt comment from Lexical editor:', error);\n return false;\n }\n }\n}\nEditorService.getEditorId = (editor) => {\n try {\n if (!editor)\n return null;\n if (!editor._config)\n return null;\n return editor._config.namespace;\n }\n catch (err) {\n VeltService.catchError('Error finding editor ID:', err);\n return null;\n }\n};\n","import { VeltService } from './velt';\nexport class StoreService {\n constructor(plugin) {\n this.isSubscribed = false;\n this.globalStore = {\n editor: null,\n comments: [],\n filteredComments: [],\n selectedCommentsMap: new Map(),\n };\n // Global annotation storage\n this.globalAnnotationStore = new Map();\n /**\n * Helper to get and set annotations with debug messages\n */\n this.annotationStore = {\n get: (id) => {\n return this.globalAnnotationStore.get(id);\n },\n set: (id, data) => {\n this.globalAnnotationStore.set(id, data);\n },\n getAll: () => {\n return new Map(this.globalAnnotationStore);\n },\n clear: () => {\n this.globalAnnotationStore.clear();\n },\n remove: (id) => {\n this.globalAnnotationStore.delete(id);\n },\n hasAnnotationTextChanged: (annotationId, currentAnnotation) => {\n try {\n const storedData = this.globalAnnotationStore.get(annotationId);\n if (!storedData || !currentAnnotation)\n return false;\n const storedText = storedData.annotation.text;\n const currentText = currentAnnotation.context?.textEditorConfig?.text;\n return storedText !== currentText;\n }\n catch (error) {\n return false;\n }\n },\n };\n this.updateGlobalStore = (store) => {\n try {\n const comments = store?.comments || this.globalStore?.comments || [];\n const newSelectedCommentsMap = store?.selectedCommentsMap || this.globalStore?.selectedCommentsMap || new Map();\n const oldFilteredComments = this.globalStore?.filteredComments || [];\n const filteredComments = comments.filter((annotation) => {\n return (annotation?.status?.type !== 'terminal' ||\n newSelectedCommentsMap?.get(annotation?.annotationId));\n });\n // Create a Set of new annotation IDs for O(1) lookup\n const newAnnotationIds = new Set(filteredComments.map((annotation) => annotation?.annotationId));\n // Get IDs of removed comments\n const removedAnnotationIds = oldFilteredComments\n .map((annotation) => annotation?.annotationId)\n .filter((id) => id && !newAnnotationIds.has(id));\n // Remove comments from editor using just IDs\n removedAnnotationIds.forEach((annotationId) => {\n if (this.globalStore?.editor && annotationId) {\n this.plugin.editorService.removeVeltCommentFromEditor(this.globalStore?.editor, annotationId);\n }\n });\n this.globalStore = { ...this.globalStore, ...store, filteredComments };\n this.highlightCommentsFromGlobalStore();\n }\n catch (error) {\n // handle error\n VeltService.catchError('Error updating global store:', error);\n }\n };\n this.highlightCommentsFromGlobalStore = () => {\n try {\n const { editor, filteredComments } = this.globalStore;\n if (!editor || !filteredComments)\n return;\n for (const annotation of filteredComments) {\n const textToFind = annotation?.context?.textEditorConfig?.text;\n const occurrence = annotation?.context?.textEditorConfig?.occurrence;\n if (textToFind) {\n this.plugin.editorService.highlightTextWithVeltComment(editor, textToFind, {\n annotationId: annotation?.annotationId,\n multiThreadAnnotationId: annotation?.multiThreadAnnotationId,\n occurrence: occurrence,\n targetTextNodeId: annotation?.context?.textEditorConfig?.targetTextNodeId,\n originalAnnotation: annotation, // Pass the complete annotation object\n });\n }\n }\n }\n catch (error) {\n // handle error\n VeltService.catchError('Error highlighting comments from global store:', error);\n }\n };\n this.plugin = plugin;\n try {\n VeltService.subscribeToSelectedCommentsMap(this.plugin.editorId, (selectedCommentsMap) => {\n try {\n this.updateGlobalStore({ selectedCommentsMap });\n }\n catch (error) {\n VeltService.catchError('Error updating global store:', error);\n }\n });\n }\n catch (error) {\n VeltService.catchError('Error subscribing to selected comments map:', error);\n }\n }\n}\nStoreService.storeInstanceMap = new Map();\n","import { EditorService } from './editor';\nimport { StoreService } from './store';\nconst instanceMap = new Map();\nexport class Plugin {\n constructor(editorId, editor) {\n this.editorId = editorId;\n this.editor = editor;\n this.editorService = new EditorService(this);\n if (editor) {\n this.editorService.initializeTransactionListener(editor);\n }\n this.storeService = new StoreService(this);\n }\n static getInstance(config) {\n let { editorId, editor } = config || {};\n if (!editorId) {\n editorId = 'default';\n }\n if (!instanceMap.has(editorId)) {\n instanceMap.set(editorId, new Plugin(editorId, editor));\n }\n return instanceMap.get(editorId);\n }\n}\n","import { createEditor, $getRoot } from \"lexical\";\nimport { $isElementNode } from \"lexical\";\nimport { $isCommentNode } from \"./comment-node\";\n/**\n * Creates a shadow editor instance for clean serialization with dynamic node configuration\n */\nfunction createShadowEditor(mainEditor) {\n // Get the main editor's creation arguments which contain the nodes configuration\n const mainCreateArgs = mainEditor._createEditorArgs;\n // Create shadow editor configuration by copying essential parts\n const shadowConfig = {\n namespace: `shadow-editor-${Date.now()}`,\n nodes: mainCreateArgs?.nodes || [],\n theme: {},\n onError: (error) => {\n // handle error\n },\n editable: false, // Shadow editor doesn't need to be editable\n };\n // Create the shadow editor (exists purely in memory)\n const shadowEditor = createEditor(shadowConfig);\n return shadowEditor;\n}\n/**\n * Serializes editor state without CommentNodes using shadow editor approach\n */\nfunction serializeWithoutComments(editor) {\n // Create a temporary shadow editor with dynamic configuration\n const shadowEditor = createShadowEditor(editor);\n try {\n // Copy the current editor state to shadow editor\n const currentState = editor.getEditorState();\n shadowEditor.setEditorState(currentState);\n // Remove comment nodes from shadow editor using proper Lexical operations\n shadowEditor.update(() => {\n const root = $getRoot();\n removeAllCommentNodesFromEditor(root);\n }, { discrete: true });\n // Get the clean JSON from shadow editor\n const cleanJson = shadowEditor.getEditorState().toJSON();\n return JSON.stringify(cleanJson);\n }\n catch (shadowError) {\n // Fallback to JSON processing if shadow editor fails\n return fallbackJsonProcessing(editor);\n }\n finally {\n // Shadow editor cleanup - since there's no destroy method, we just let it be garbage collected\n // The shadow editor exists only in memory and will be cleaned up by garbage collection\n }\n}\n/**\n * Removes all comment nodes from the editor tree using proper Lexical operations\n */\nfunction removeAllCommentNodesFromEditor(node) {\n const commentNodesToRemove = [];\n // First pass: collect all comment nodes\n function collectCommentNodes(currentNode) {\n if ($isCommentNode(currentNode)) {\n commentNodesToRemove.push(currentNode);\n }\n else if ($isElementNode(currentNode)) {\n const children = currentNode.getChildren();\n children.forEach(collectCommentNodes);\n }\n }\n collectCommentNodes(node);\n // Second pass: remove comment nodes and unwrap their content\n commentNodesToRemove.forEach((commentNode) => {\n try {\n const parent = commentNode.getParent();\n if (!parent)\n return;\n const children = commentNode.getChildren();\n const insertIndex = commentNode.getIndexWithinParent();\n // Remove the comment node first\n commentNode.remove();\n // Insert the unwrapped children where the comment node was\n if (children.length > 0) {\n parent.splice(insertIndex, 0, children);\n }\n }\n catch (error) {\n // handle error\n }\n });\n // Let Lexical normalize the tree (merge adjacent text nodes, etc.)\n node.markDirty();\n}\n/**\n * Fallback JSON processing method when shadow editor fails\n */\nfunction fallbackJsonProcessing(editor) {\n return editor.getEditorState().read(() => {\n const json = editor.getEditorState().toJSON();\n const cleanJson = removeCommentNodesFromJSON(json);\n const normalizedJson = normalizeTextNodesInJSON(cleanJson);\n return JSON.stringify(normalizedJson);\n });\n}\n/**\n * Recursively removes CommentNodes from JSON while preserving their text content\n */\nfunction removeCommentNodesFromJSON(json) {\n if (!json || typeof json !== 'object') {\n return json;\n }\n // Handle arrays (like children arrays)\n if (Array.isArray(json)) {\n const cleanArray = [];\n for (const item of json) {\n if (item && item.type === 'comment') {\n // Extract children from CommentNode and add them directly\n if (item.children && Array.isArray(item.children)) {\n for (const child of item.children) {\n cleanArray.push(removeCommentNodesFromJSON(child));\n }\n }\n }\n else {\n cleanArray.push(removeCommentNodesFromJSON(item));\n }\n }\n return cleanArray;\n }\n // Handle objects\n const cleanObj = { ...json };\n // If this is a CommentNode, return its children instead\n if (cleanObj.type === 'comment') {\n if (cleanObj.children && Array.isArray(cleanObj.children)) {\n // Return the children directly, not wrapped in the comment\n return cleanObj.children.map((child) => removeCommentNodesFromJSON(child));\n }\n return null; // Remove empty comment nodes\n }\n // For other objects, recursively clean their properties\n for (const [key, value] of Object.entries(cleanObj)) {\n if (key === 'children' && Array.isArray(value)) {\n cleanObj[key] = removeCommentNodesFromJSON(value);\n }\n else if (typeof value === 'object' && value !== null) {\n cleanObj[key] = removeCommentNodesFromJSON(value);\n }\n }\n return cleanObj;\n}\n/**\n * Normalizes adjacent text nodes in JSON (merges text nodes with same formatting)\n */\nfunction normalizeTextNodesInJSON(json) {\n if (!json || typeof json !== 'object') {\n return json;\n }\n if (Array.isArray(json)) {\n return json.map(item => normalizeTextNodesInJSON(item));\n }\n const normalizedObj = { ...json };\n // Process children array if it exists\n if (normalizedObj.children && Array.isArray(normalizedObj.children)) {\n const children = normalizedObj.children.map((child) => normalizeTextNodesInJSON(child));\n normalizedObj.children = mergeAdjacentTextNodes(children);\n }\n // Recursively process other object properties\n for (const [key, value] of Object.entries(normalizedObj)) {\n if (key !== 'children' && typeof value === 'object' && value !== null) {\n normalizedObj[key] = normalizeTextNodesInJSON(value);\n }\n }\n return normalizedObj;\n}\n/**\n * Merges adjacent text nodes with the same formatting in a children array\n */\nfunction mergeAdjacentTextNodes(children) {\n if (!Array.isArray(children) || children.length <= 1) {\n return children;\n }\n const merged = [];\n let i = 0;\n while (i < children.length) {\n const current = children[i];\n if (current && current.type === 'text') {\n let mergedText = current.text || '';\n let j = i + 1;\n // Look for adjacent text nodes with same formatting\n while (j < children.length) {\n const next = children[j];\n if (next && next.type === 'text' && haveSameTextFormat(current, next)) {\n mergedText += next.text || '';\n j++;\n }\n else {\n break;\n }\n }\n // Create merged text node\n merged.push({\n ...current,\n text: mergedText\n });\n i = j; // Move to next unprocessed node\n }\n else {\n merged.push(current);\n i++;\n }\n }\n return merged;\n}\n/**\n * Checks if two text nodes have the same formatting\n */\nfunction haveSameTextFormat(node1, node2) {\n return (node1.format === node2.format &&\n node1.style === node2.style &&\n node1.mode === node2.mode &&\n node1.detail === node2.detail);\n}\n/**\n * Enhanced export function with multiple strategies\n */\nexport const exportCleanEditorContent = (editor) => {\n try {\n return serializeWithoutComments(editor);\n }\n catch (error) {\n return editor.getEditorState().read(() => {\n const root = $getRoot();\n return JSON.stringify({\n root: {\n children: [{\n children: [{\n detail: 0,\n format: 0,\n mode: \"normal\",\n style: \"\",\n text: root.getTextContent(),\n type: \"text\",\n version: 1\n }],\n direction: \"ltr\",\n format: \"\",\n indent: 0,\n type: \"paragraph\",\n version: 1,\n textFormat: 0,\n textStyle: \"\"\n }],\n direction: \"ltr\",\n format: \"\",\n indent: 0,\n type: \"root\",\n version: 1\n }\n });\n });\n }\n};\n/**\n * Deserializes editor state from clean JSON\n */\nexport function deserializeCleanState(editor, jsonString) {\n try {\n const json = JSON.parse(jsonString);\n editor.setEditorState(editor.parseEditorState(json));\n }\n catch (error) {\n // Fallback to empty state\n editor.update(() => {\n const root = $getRoot();\n root.clear();\n });\n }\n}\n","import { EditorService } from \"./editor\";\nimport { Plugin } from \"./plugin\";\nimport { VeltService } from \"./velt\";\nexport * from './comment-node';\nexport * from './serializer';\nconst VELT_SDK_VERSION = '4.5.2-beta.1';\nexport const triggerAddComment = async (editor, config) => {\n try {\n return addComment({ editor, context: config?.context });\n }\n catch (error) {\n VeltService.catchError('Error triggering add comment', error);\n }\n};\n/**\n * Creates a comment annotation for the currently selected text in the editor\n * This function handles the entire flow from getting the selected text to creating\n * the actual comment through the Velt service\n */\nexport const addComment = async ({ editorId, editor, context: clientContext, }) => {\n try {\n // get comment element from Velt sdk\n const commentElement = VeltService.getCommentElement();\n if (!commentElement)\n return;\n // add 500ms delay\n await new Promise(resolve => setTimeout(resolve, 500));\n // Ensure we have an editor ID for proper tracking\n if (!editorId) {\n editorId = EditorService.getEditorId(editor) ?? undefined;\n }\n // Initialize plugin instance with editor context\n const plugin = Plugin.getInstance({ editorId, editor });\n // let context: any = {};\n // if (config?.context && typeof config.context === 'object') {\n // context = config.context;\n // }\n // Get text currently selected by the user\n const selectedText = plugin.editorService.getSelectedText(editor);\n // Exit if no text is selected - nothing to comment on\n if (!selectedText) {\n return;\n }\n // const targetTextNode = plugin.editorService.findParentNodeWithId(editor);\n let targetTextNodeId = undefined;\n let locationId = undefined;\n // if (targetTextNode) {\n // targetTextNodeId = targetTextNode.id;\n // locationId = targetTextNode.closest(`[${Constants.ATTRIBUTES.LOCATION_ID}]`)?.getAttribute(Constants.ATTRIBUTES.LOCATION_ID);\n // }\n // Calculate which occurrence of the text this selection represents using the new function\n // const currentSelectionFrom = editor.state.selection.from;\n // const currentSelectionTo = editor.state.selection.to;\n const occurrence = plugin.editorService.findOccurrenceIndex(editor, selectedText, null);\n // Exit if we can't determine occurrence information\n if (!occurrence) {\n return;\n }\n // Initialize context object for the comment\n let context = {};\n if (clientContext && typeof clientContext === 'object') {\n context = { ...context, ...clientContext };\n }\n context.textEditorConfig = {\n text: selectedText,\n occurrence: occurrence,\n targetTextNodeId: targetTextNodeId,\n };\n if (editorId) {\n context.textEditorConfig.editorId = editorId;\n }\n let location = undefined;\n if (locationId) {\n location = { id: locationId };\n }\n commentElement?.addManualComment({ context, location })?.then((data) => { });\n }\n catch (error) {\n VeltService.catchError('Error adding lexical-velt-comments', error);\n }\n};\nexport function highlightComments(editor, commentAnnotations, editorId) {\n try {\n renderComments({ editor, editorId, commentAnnotations });\n }\n catch (error) {\n VeltService.catchError('Error highlighting lexical-velt-comments', error);\n }\n}\nexport const renderComments = ({ editor, editorId, commentAnnotations }) => {\n try {\n if (editor) {\n if (!editorId) {\n editorId = EditorService.getEditorId(editor) ?? undefined;\n }\n if (!Array.isArray(commentAnnotations)) {\n return;\n }\n commentAnnotations = JSON.parse(JSON.stringify(commentAnnotations));\n const lexicalCommentAnnotations = commentAnnotations\n ?.filter((annotation) => !!annotation.context?.textEditorConfig &&\n annotation.context?.textEditorConfig?.editorId === editorId) || [];\n const plugin = Plugin.getInstance({ editorId, editor });\n plugin.storeService.updateGlobalStore({ editor, comments: lexicalCommentAnnotations });\n VeltService.subscribeToSelectedAnnotationsMapSingleton();\n }\n }\n catch (error) {\n VeltService.catchError('Error highlighting lexical-velt-comments', error);\n }\n};\n"],"names":["_a","CommentNode","ElementNode","getType","clone","node","__annotationId","__multiThreadAnnotationId","__key","constructor","annotationId","multiThreadAnnotationId","key","super","this","createDOM","config","dom","document","createElement","setAttribute","updateDOM","prevNode","importJSON","serializedNode","$createCommentNode","exportJSON","type","version","isInline","$isCommentNode","VeltService","selectedCommentsMap","Map","subscribers","isSubscribed","getCommentElement","velt","window","Velt","error","catchError","addManualComment","context","location","commentElement","Promise","resolve","updateContext","subscribeToSelectedCommentsMap","id","subscriber","subscribeToSelectedAnnotationsMapSingleton","set","unsubscribeFromSelectedCommentsMap","delete","message","otherProperties","properties","sdkVersion","getSelectedComments","subscribe","comments","forEach","comment","map1","map2","size","value","get","areMapsEqual","updateSelectedCommentsMap","EditorService","plugin","initializeTransactionListener","editor","editorUpdateListenerRemover","registerUpdateListener","editorState","prevEditorState","hasDocumentChanged","onTransaction","err","destroyTransactionListener","undefined","currentState","prevState","read","currentText","$getRoot","getTextContent","prevText","changedAnnotationContent","annotationsToCheck","collectDocumentAnnotations","data","Array","from","entries","changes","processAnnotationChanges","updateVeltComments","getCommentNodeTextWithStructure","commentNode","text","traverse","depth","$isTextNode","$isElementNode","children","getChildren","nodeType","i","length","parent","getParent","siblings","indexOf","self","getEditorState","root","currentPosition","prevAnnotationData","storeService","annotationStore","nodeSize","existingAnnotation","nodeData","pos","nodes","push","annotation","originalText","textEditorConfig","originalOccurrence","occurrence","targetTextNodeId","child","Error","isArray","contentChanged","detectContentChanges","targetTextNodeIdChanged","newTargetTextNodeId","searchResults","detectContainerChanges","currentOccurrence","calculateNewOccurrence","occurrenceChanged","createAnnotationChange","sortedNodes","sort","a","b","includes","map","n","join","params","containerChangeResult","processContainerChanges","changed","newId","findTextInDomElement","findTextInDocument","foundNodePosition","currentPos","editorDOMElement","getRootElement","querySelector","newContainer","findNewContainer","newSearchResults","editorElement","elementsWithIds","querySelectorAll","element","textContent","firstNode","lastNode","annotationRange","result","start","end","originalTargetTextNodeId","changeData","JSON","parse","stringify","remove","removeVeltCommentFromEditor","setTimeout","getSelectedText","selection","$getSelection","$isRangeSelection","findOccurrenceIndex","selectedText","targetContainer","trim","matches","selectionStart","selectionEnd","range","getSelectionTextRange","findTextInContainer","findTextInEditor","nodeMap","collectTextContent","anchorNode","anchor","getNode","focusNode","focus","anchorOffset","offset","focusOffset","anchorTextPos","focusTextPos","item","isParagraphBreak","nodeKey","getKey","Math","min","max","combinedText","currentOffset","startOffset","endOffset","searchText","positions","kmpSearch","containerId","containerElement","getElementById","containerContent","getContainerTextContent","containerStartOffset","containerEndOffset","nodeDOMElement","getElementByKey","contains","substring","filterNodesInContainer","textNodes","containerNodes","textNodeData","collectTextNodes","currentTextOffset","textOffset","getTextNodesInRange","fromPos","toPos","excludeAnnotationId","isPartial","isRangeAlreadyWrapped","foundWrapping","nodeStart","nodeEnd","collectTextNodesInRange","getContainerRange","containerText","startIndex","pattern","startPos","maxOccurrences","lps","computeKMPTable","j","fill","len","findParentContainerWithId","current","body","parentElement","highlightTextWithVeltComment","textToFind","commentOptions","desiredOccurrence","storedData","storedConfig","newConfig","originalAnnotation","domNode","locationId","closest","getAttribute","matchToConsider","pluginReference","position","to","setVeltComment","domElementId","containerTextNodes","update","selectStart","textNodesToWrap","wrapPartialTextNode","wrapEntireTextNode","wrapMultipleTextNodesWithFormatting","textNode","writableNode","getWritable","fullText","beforeText","afterText","selectedTextNode","$createTextNode","setFormat","getFormat","setStyle","getStyle","append","beforeNode","insertBefore","afterNode","parentWritable","nodeIndex","getIndexWithinParent","splice","nodesByParagraph","paragraphParent","findParagraphParent","paragraphKey","has","isFirstParagraph","nodesInParagraph","paragraphCommentNode","wrapMultipleNodesInSameParagraph","firstNodeData","lastNodeData","insertionIndex","selectedPartNode","replace","nodesRemoved","commentNodesToRemove","firstChild","insertAfter","nodeError","getEditorId","_config","namespace","StoreService","globalStore","filteredComments","globalAnnotationStore","getAll","clear","hasAnnotationTextChanged","currentAnnotation","storedText","updateGlobalStore","store","newSelectedCommentsMap","oldFilteredComments","filter","status","newAnnotationIds","Set","editorService","highlightCommentsFromGlobalStore","editorId","storeInstanceMap","instanceMap","Plugin","getInstance","serializeWithoutComments","shadowEditor","mainEditor","mainCreateArgs","_createEditorArgs","shadowConfig","Date","now","theme","onError","editable","createEditor","createShadowEditor","setEditorState","collectCommentNodes","currentNode","insertIndex","markDirty","removeAllCommentNodesFromEditor","discrete","cleanJson","toJSON","shadowError","normalizedJson","normalizeTextNodesInJSON","removeCommentNodesFromJSON","fallbackJsonProcessing","json","cleanArray","cleanObj","Object","normalizedObj","merged","mergedText","next","haveSameTextFormat","mergeAdjacentTextNodes","node1","node2","format","style","mode","detail","addComment","async","clientContext","then","renderComments","commentAnnotations","lexicalCommentAnnotations","jsonString","parseEditorState","direction","indent","textFormat","textStyle"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { EditorConfig, LexicalNode, NodeKey, SerializedElementNode, Spread } from 'lexical';
|
|
2
|
+
import { ElementNode } from 'lexical';
|
|
3
|
+
type SerializedCommentNode = Spread<{
|
|
4
|
+
annotationId?: string;
|
|
5
|
+
multiThreadAnnotationId?: string;
|
|
6
|
+
type: 'comment';
|
|
7
|
+
version: 1;
|
|
8
|
+
}, SerializedElementNode>;
|
|
9
|
+
export declare class CommentNode extends ElementNode {
|
|
10
|
+
__annotationId?: string;
|
|
11
|
+
__multiThreadAnnotationId?: string;
|
|
12
|
+
static getType(): string;
|
|
13
|
+
static clone(node: CommentNode): CommentNode;
|
|
14
|
+
constructor(annotationId?: string, multiThreadAnnotationId?: string, key?: NodeKey);
|
|
15
|
+
createDOM(config: EditorConfig): HTMLElement;
|
|
16
|
+
updateDOM(prevNode: CommentNode, dom: HTMLElement, config: EditorConfig): boolean;
|
|
17
|
+
static importJSON(serializedNode: SerializedCommentNode): CommentNode;
|
|
18
|
+
exportJSON(): SerializedCommentNode;
|
|
19
|
+
isInline(): boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function $createCommentNode(annotationId?: string, multiThreadAnnotationId?: string): CommentNode;
|
|
22
|
+
export declare function $isCommentNode(node: LexicalNode | null | undefined): node is CommentNode;
|
|
23
|
+
export {};
|