chore: upgrade lexical (#2889)

This commit is contained in:
Aman Harwara 2025-01-02 13:31:40 +05:30 committed by GitHub
parent 5c23a11b5a
commit 1456950a63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 700 additions and 1288 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,151 +0,0 @@
diff --git a/LexicalClipboard.dev.js b/LexicalClipboard.dev.js
index 3fad3811aa254c5b1b02e039c0d1f21c2a28562f..78aa3bc5048bb4354339efc558031ec0185163dd 100644
--- a/LexicalClipboard.dev.js
+++ b/LexicalClipboard.dev.js
@@ -30,7 +30,6 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
* LICENSE file in the root directory of this source tree.
*
*/
-
const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
/**
@@ -105,7 +104,7 @@ function $insertDataTransferForPlainText(dataTransfer, selection) {
* @param selection the selection to use as the insertion point for the content in the DataTransfer object
* @param editor the LexicalEditor the content is being inserted into.
*/
-function $insertDataTransferForRichText(dataTransfer, selection, editor) {
+function $insertDataTransferForRichText(dataTransfer, selection, editor, event) {
const lexicalString = dataTransfer.getData('application/x-lexical-editor');
if (lexicalString) {
try {
@@ -118,15 +117,18 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) {
// Fail silently.
}
}
- const htmlString = dataTransfer.getData('text/html');
- if (htmlString) {
- try {
- const parser = new DOMParser();
- const dom = parser.parseFromString(htmlString, 'text/html');
- const nodes = html.$generateNodesFromDOM(editor, dom);
- return $insertGeneratedNodes(editor, nodes, selection);
- } catch (_unused2) {
- // Fail silently.
+ const shouldIgnoreHTML = event && event.inputType === 'insertReplacementText' && dataTransfer.types.includes('text/plain');
+ if (!shouldIgnoreHTML) {
+ const htmlString = dataTransfer.getData('text/html');
+ if (htmlString) {
+ try {
+ const parser = new DOMParser();
+ const dom = parser.parseFromString(htmlString, 'text/html');
+ const nodes = html.$generateNodesFromDOM(editor, dom);
+ return $insertGeneratedNodes(editor, nodes, selection);
+ } catch (_unused2) {
+ // Fail silently.
+ }
}
}
diff --git a/LexicalClipboard.dev.mjs b/LexicalClipboard.dev.mjs
index 9d1054125804bec18b6d2fc3b09386defa7c8be2..ef944d097da9cc4383c38c874a6d1e7c20ab22d0 100644
--- a/LexicalClipboard.dev.mjs
+++ b/LexicalClipboard.dev.mjs
@@ -28,7 +28,6 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
* LICENSE file in the root directory of this source tree.
*
*/
-
const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
/**
@@ -103,7 +102,7 @@ function $insertDataTransferForPlainText(dataTransfer, selection) {
* @param selection the selection to use as the insertion point for the content in the DataTransfer object
* @param editor the LexicalEditor the content is being inserted into.
*/
-function $insertDataTransferForRichText(dataTransfer, selection, editor) {
+function $insertDataTransferForRichText(dataTransfer, selection, editor, event) {
const lexicalString = dataTransfer.getData('application/x-lexical-editor');
if (lexicalString) {
try {
@@ -116,15 +115,18 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) {
// Fail silently.
}
}
- const htmlString = dataTransfer.getData('text/html');
- if (htmlString) {
- try {
- const parser = new DOMParser();
- const dom = parser.parseFromString(htmlString, 'text/html');
- const nodes = $generateNodesFromDOM(editor, dom);
- return $insertGeneratedNodes(editor, nodes, selection);
- } catch (_unused2) {
- // Fail silently.
+ const shouldIgnoreHTML = event && event.inputType === 'insertReplacementText' && dataTransfer.types.includes('text/plain');
+ if (!shouldIgnoreHTML) {
+ const htmlString = dataTransfer.getData('text/html');
+ if (htmlString) {
+ try {
+ const parser = new DOMParser();
+ const dom = parser.parseFromString(htmlString, 'text/html');
+ const nodes = $generateNodesFromDOM(editor, dom);
+ return $insertGeneratedNodes(editor, nodes, selection);
+ } catch (_unused2) {
+ // Fail silently.
+ }
}
}
diff --git a/LexicalClipboard.prod.js b/LexicalClipboard.prod.js
index 38848b4d69dcae7d54a5ab99b8f3cdd9324e413f..7ddc6b87dd2c9c32973f4dc7ae552c8fdb80eeb0 100644
--- a/LexicalClipboard.prod.js
+++ b/LexicalClipboard.prod.js
@@ -6,14 +6,14 @@
*
*/
-'use strict';var f=require("@lexical/html"),m=require("@lexical/selection"),n=require("@lexical/utils"),p=require("lexical"),t;function u(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}
-t=u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u["default"]:u;let v="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement;function w(a){let b=p.$getSelection();null==b&&t(166);return p.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?"":f.$generateHtmlFromNodes(a,b)}
-function x(a){let b=p.$getSelection();null==b&&t(166);return p.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?null:JSON.stringify(y(a,b))}function z(a,b,c){a.dispatchCommand(p.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND,{nodes:b,selection:c})||c.insertNodes(b)}
-function A(a,b,c,d=[]){let e=null!==b?c.isSelected(b):!0,h=p.$isElementNode(c)&&c.excludeFromCopy("html");var g=c;if(null!==b){var k=m.$cloneWithProperties(c);g=k=p.$isTextNode(k)&&null!==b?m.$sliceSelectedTextNodeContent(b,k):k}let q=p.$isElementNode(g)?g.getChildren():[];var l=g;k=l.exportJSON();var r=l.constructor;k.type!==r.getType()&&t(58,r.name);p.$isElementNode(l)&&(Array.isArray(k.children)||t(59,r.name));p.$isTextNode(g)&&(g=g.__text,0<g.length?k.text=g:e=!1);for(g=0;g<q.length;g++)l=q[g],
-r=A(a,b,l,k.children),!e&&p.$isElementNode(c)&&r&&c.extractWithChild(l,b,"clone")&&(e=!0);if(e&&!h)d.push(k);else if(Array.isArray(k.children))for(a=0;a<k.children.length;a++)d.push(k.children[a]);return e}function y(a,b){let c=[],d=p.$getRoot().getChildren();for(let e=0;e<d.length;e++)A(a,b,d[e],c);return{namespace:a._config.namespace,nodes:c}}function B(a){let b=[];for(let c=0;c<a.length;c++){let d=p.$parseSerializedNode(a[c]);p.$isTextNode(d)&&m.$addNodeStyle(d);b.push(d)}return b}let C=null;
-function D(a,b){var c=v?(a._window||window).getSelection():null;if(!c)return!1;var d=c.anchorNode;c=c.focusNode;if(null!==d&&null!==c&&!p.isSelectionWithinEditor(a,d,c))return!1;b.preventDefault();b=b.clipboardData;d=p.$getSelection();if(null===b||null===d)return!1;c=w(a);a=x(a);let e="";null!==d&&(e=d.getTextContent());null!==c&&b.setData("text/html",c);null!==a&&b.setData("application/x-lexical-editor",a);b.setData("text/plain",e);return!0}exports.$generateJSONFromSelectedNodes=y;
-exports.$generateNodesFromSerializedNodes=B;exports.$getHtmlContent=w;exports.$getLexicalContent=x;exports.$insertDataTransferForPlainText=function(a,b){a=a.getData("text/plain")||a.getData("text/uri-list");null!=a&&b.insertRawText(a)};
-exports.$insertDataTransferForRichText=function(a,b,c){var d=a.getData("application/x-lexical-editor");if(d)try{let h=JSON.parse(d);if(h.namespace===c._config.namespace&&Array.isArray(h.nodes)){let g=B(h.nodes);return z(c,g,b)}}catch(h){}if(d=a.getData("text/html"))try{var e=(new DOMParser).parseFromString(d,"text/html");let h=f.$generateNodesFromDOM(c,e);return z(c,h,b)}catch(h){}a=a.getData("text/plain")||a.getData("text/uri-list");if(null!=a)if(p.$isRangeSelection(b))for(b=a.split(/(\r?\n|\t)/),
-""===b[b.length-1]&&b.pop(),a=0;a<b.length;a++)c=p.$getSelection(),p.$isRangeSelection(c)&&(e=b[a],"\n"===e||"\r\n"===e?c.insertParagraph():"\t"===e?c.insertNodes([p.$createTabNode()]):c.insertText(e));else b.insertRawText(a)};exports.$insertGeneratedNodes=z;
-exports.copyToClipboard=async function(a,b){if(null!==C)return!1;if(null!==b)return new Promise(g=>{a.update(()=>{g(D(a,b))})});var c=a.getRootElement();let d=null==a._window?window.document:a._window.document,e=v?(a._window||window).getSelection():null;if(null===c||null===e)return!1;let h=d.createElement("span");h.style.cssText="position: fixed; top: -1000px;";h.append(d.createTextNode("#"));c.append(h);c=new Range;c.setStart(h,0);c.setEnd(h,1);e.removeAllRanges();e.addRange(c);return new Promise(g=>
-{let k=a.registerCommand(p.COPY_COMMAND,q=>{n.objectKlassEquals(q,ClipboardEvent)&&(k(),null!==C&&(window.clearTimeout(C),C=null),g(D(a,q)));return!0},p.COMMAND_PRIORITY_CRITICAL);C=window.setTimeout(()=>{k();C=null;g(!1)},50);d.execCommand("copy");h.remove()})}
+'use strict';var f=require("@lexical/html"),m=require("@lexical/selection"),q=require("@lexical/utils"),r=require("lexical");function t(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}
+let u="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement;function v(a){let b=r.$getSelection();null==b&&t(166);return r.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?"":f.$generateHtmlFromNodes(a,b)}function w(a){let b=r.$getSelection();null==b&&t(166);return r.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?null:JSON.stringify(x(a,b))}
+function y(a,b,c){a.dispatchCommand(r.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND,{nodes:b,selection:c})||c.insertNodes(b)}
+function z(a,b,c,e=[]){let g=null!==b?c.isSelected(b):!0,k=r.$isElementNode(c)&&c.excludeFromCopy("html");var d=c;if(null!==b){var h=m.$cloneWithProperties(c);d=h=r.$isTextNode(h)&&null!==b?m.$sliceSelectedTextNodeContent(b,h):h}let n=r.$isElementNode(d)?d.getChildren():[];var l=d;h=l.exportJSON();var p=l.constructor;h.type!==p.getType()&&t(58,p.name);r.$isElementNode(l)&&(Array.isArray(h.children)||t(59,p.name));r.$isTextNode(d)&&(d=d.__text,0<d.length?h.text=d:g=!1);for(d=0;d<n.length;d++)l=n[d],
+p=z(a,b,l,h.children),!g&&r.$isElementNode(c)&&p&&c.extractWithChild(l,b,"clone")&&(g=!0);if(g&&!k)e.push(h);else if(Array.isArray(h.children))for(a=0;a<h.children.length;a++)e.push(h.children[a]);return g}function x(a,b){let c=[],e=r.$getRoot().getChildren();for(let g=0;g<e.length;g++)z(a,b,e[g],c);return{namespace:a._config.namespace,nodes:c}}function A(a){let b=[];for(let c=0;c<a.length;c++){let e=r.$parseSerializedNode(a[c]);r.$isTextNode(e)&&m.$addNodeStyle(e);b.push(e)}return b}let B=null;
+function C(a,b){var c=u?(a._window||window).getSelection():null;if(!c)return!1;var e=c.anchorNode;c=c.focusNode;if(null!==e&&null!==c&&!r.isSelectionWithinEditor(a,e,c))return!1;b.preventDefault();b=b.clipboardData;e=r.$getSelection();if(null===b||null===e)return!1;c=v(a);a=w(a);let g="";null!==e&&(g=e.getTextContent());null!==c&&b.setData("text/html",c);null!==a&&b.setData("application/x-lexical-editor",a);b.setData("text/plain",g);return!0}exports.$generateJSONFromSelectedNodes=x;
+exports.$generateNodesFromSerializedNodes=A;exports.$getHtmlContent=v;exports.$getLexicalContent=w;exports.$insertDataTransferForPlainText=function(a,b){a=a.getData("text/plain")||a.getData("text/uri-list");null!=a&&b.insertRawText(a)};
+exports.$insertDataTransferForRichText=function(a,b,c,e){let g=a.getData("application/x-lexical-editor");if(g)try{let d=JSON.parse(g);if(d.namespace===c._config.namespace&&Array.isArray(d.nodes)){let h=A(d.nodes);return y(c,h,b)}}catch(d){}if(!e||"insertReplacementText"!==e.inputType||!a.types.includes("text/plain"))if(e=a.getData("text/html"))try{var k=(new DOMParser).parseFromString(e,"text/html");let d=f.$generateNodesFromDOM(c,k);return y(c,d,b)}catch(d){}a=a.getData("text/plain")||a.getData("text/uri-list");
+if(null!=a)if(r.$isRangeSelection(b))for(b=a.split(/(\r?\n|\t)/),""===b[b.length-1]&&b.pop(),a=0;a<b.length;a++)c=r.$getSelection(),r.$isRangeSelection(c)&&(k=b[a],"\n"===k||"\r\n"===k?c.insertParagraph():"\t"===k?c.insertNodes([r.$createTabNode()]):c.insertText(k));else b.insertRawText(a)};exports.$insertGeneratedNodes=y;
+exports.copyToClipboard=async function(a,b){if(null!==B)return!1;if(null!==b)return new Promise(d=>{a.update(()=>{d(C(a,b))})});var c=a.getRootElement();let e=null==a._window?window.document:a._window.document,g=u?(a._window||window).getSelection():null;if(null===c||null===g)return!1;let k=e.createElement("span");k.style.cssText="position: fixed; top: -1000px;";k.append(e.createTextNode("#"));c.append(k);c=new Range;c.setStart(k,0);c.setEnd(k,1);g.removeAllRanges();g.addRange(c);return new Promise(d=>
+{let h=a.registerCommand(r.COPY_COMMAND,n=>{q.objectKlassEquals(n,ClipboardEvent)&&(h(),null!==B&&(window.clearTimeout(B),B=null),d(C(a,n)));return!0},r.COMMAND_PRIORITY_CRITICAL);B=window.setTimeout(()=>{h();B=null;d(!1)},50);e.execCommand("copy");k.remove()})}
diff --git a/LexicalClipboard.prod.mjs b/LexicalClipboard.prod.mjs
index 6b572db295155b182e3077f64b308cbbf993e241..32076e8a14b02d37e0a8302e51920f13dc211180 100644
--- a/LexicalClipboard.prod.mjs
+++ b/LexicalClipboard.prod.mjs
@@ -6,4 +6,4 @@
*
*/
-import{$generateHtmlFromNodes as t,$generateNodesFromDOM as e}from"@lexical/html";import{$addNodeStyle as n,$cloneWithProperties as o,$sliceSelectedTextNodeContent as l}from"@lexical/selection";import{objectKlassEquals as r}from"@lexical/utils";import{$getSelection as i,$isRangeSelection as s,$createTabNode as a,SELECTION_INSERT_CLIPBOARD_NODES_COMMAND as c,$getRoot as u,$parseSerializedNode as d,$isTextNode as f,COPY_COMMAND as p,COMMAND_PRIORITY_CRITICAL as m,isSelectionWithinEditor as h,$isElementNode as g}from"lexical";function x(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var w=x((function(t){const e=new URLSearchParams;e.append("code",t);for(let t=1;t<arguments.length;t++)e.append("v",arguments[t]);throw Error(`Minified Lexical error #${t}; visit https://lexical.dev/docs/error?${e} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));const y="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,v=t=>y?(t||window).getSelection():null;function D(e){const n=i();return null==n&&w(166),s(n)&&n.isCollapsed()||0===n.getNodes().length?"":t(e,n)}function C(t){const e=i();return null==e&&w(166),s(e)&&e.isCollapsed()||0===e.getNodes().length?null:JSON.stringify(A(t,e))}function N(t,e){const n=t.getData("text/plain")||t.getData("text/uri-list");null!=n&&e.insertRawText(n)}function _(t,n,o){const l=t.getData("application/x-lexical-editor");if(l)try{const t=JSON.parse(l);if(t.namespace===o._config.namespace&&Array.isArray(t.nodes)){return T(o,R(t.nodes),n)}}catch(t){}const r=t.getData("text/html");if(r)try{const t=(new DOMParser).parseFromString(r,"text/html");return T(o,e(o,t),n)}catch(t){}const c=t.getData("text/plain")||t.getData("text/uri-list");if(null!=c)if(s(n)){const t=c.split(/(\r?\n|\t)/);""===t[t.length-1]&&t.pop();for(let e=0;e<t.length;e++){const n=i();if(s(n)){const o=t[e];"\n"===o||"\r\n"===o?n.insertParagraph():"\t"===o?n.insertNodes([a()]):n.insertText(o)}}}else n.insertRawText(c)}function T(t,e,n){t.dispatchCommand(c,{nodes:e,selection:n})||n.insertNodes(e)}function S(t,e,n,r=[]){let i=null===e||n.isSelected(e);const s=g(n)&&n.excludeFromCopy("html");let a=n;if(null!==e){let t=o(n);t=f(t)&&null!==e?l(e,t):t,a=t}const c=g(a)?a.getChildren():[],u=function(t){const e=t.exportJSON(),n=t.constructor;if(e.type!==n.getType()&&w(58,n.name),g(t)){const t=e.children;Array.isArray(t)||w(59,n.name)}return e}(a);if(f(a)){const t=a.__text;t.length>0?u.text=t:i=!1}for(let o=0;o<c.length;o++){const l=c[o],r=S(t,e,l,u.children);!i&&g(n)&&r&&n.extractWithChild(l,e,"clone")&&(i=!0)}if(i&&!s)r.push(u);else if(Array.isArray(u.children))for(let t=0;t<u.children.length;t++){const e=u.children[t];r.push(e)}return i}function A(t,e){const n=[],o=u().getChildren();for(let l=0;l<o.length;l++){S(t,e,o[l],n)}return{namespace:t._config.namespace,nodes:n}}function R(t){const e=[];for(let o=0;o<t.length;o++){const l=t[o],r=d(l);f(r)&&n(r),e.push(r)}return e}let E=null;async function O(t,e){if(null!==E)return!1;if(null!==e)return new Promise(((n,o)=>{t.update((()=>{n(P(t,e))}))}));const n=t.getRootElement(),o=null==t._window?window.document:t._window.document,l=v(t._window);if(null===n||null===l)return!1;const i=o.createElement("span");i.style.cssText="position: fixed; top: -1000px;",i.append(o.createTextNode("#")),n.append(i);const s=new Range;return s.setStart(i,0),s.setEnd(i,1),l.removeAllRanges(),l.addRange(s),new Promise(((e,n)=>{const l=t.registerCommand(p,(n=>(r(n,ClipboardEvent)&&(l(),null!==E&&(window.clearTimeout(E),E=null),e(P(t,n))),!0)),m);E=window.setTimeout((()=>{l(),E=null,e(!1)}),50),o.execCommand("copy"),i.remove()}))}function P(t,e){const n=v(t._window);if(!n)return!1;const o=n.anchorNode,l=n.focusNode;if(null!==o&&null!==l&&!h(t,o,l))return!1;e.preventDefault();const r=e.clipboardData,s=i();if(null===r||null===s)return!1;const a=D(t),c=C(t);let u="";return null!==s&&(u=s.getTextContent()),null!==a&&r.setData("text/html",a),null!==c&&r.setData("application/x-lexical-editor",c),r.setData("text/plain",u),!0}export{A as $generateJSONFromSelectedNodes,R as $generateNodesFromSerializedNodes,D as $getHtmlContent,C as $getLexicalContent,N as $insertDataTransferForPlainText,_ as $insertDataTransferForRichText,T as $insertGeneratedNodes,O as copyToClipboard};
+import{$generateHtmlFromNodes as e,$generateNodesFromDOM as t}from"@lexical/html";import{$addNodeStyle as n,$cloneWithProperties as l,$sliceSelectedTextNodeContent as o}from"@lexical/selection";import{objectKlassEquals as r}from"@lexical/utils";import{$getSelection as i,$isRangeSelection as s,$createTabNode as a,SELECTION_INSERT_CLIPBOARD_NODES_COMMAND as c,$getRoot as u,$parseSerializedNode as d,$isTextNode as p,COPY_COMMAND as f,COMMAND_PRIORITY_CRITICAL as m,isSelectionWithinEditor as h,$isElementNode as g}from"lexical";var x=function(e){const t=new URLSearchParams;t.append("code",e);for(let e=1;e<arguments.length;e++)t.append("v",arguments[e]);throw Error(`Minified Lexical error #${e}; visit https://lexical.dev/docs/error?${t} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)};const w="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement,y=e=>w?(e||window).getSelection():null;function v(t){const n=i();return null==n&&x(166),s(n)&&n.isCollapsed()||0===n.getNodes().length?"":e(t,n)}function D(e){const t=i();return null==t&&x(166),s(t)&&t.isCollapsed()||0===t.getNodes().length?null:JSON.stringify(S(e,t))}function C(e,t){const n=e.getData("text/plain")||e.getData("text/uri-list");null!=n&&t.insertRawText(n)}function T(e,n,l,o){const r=e.getData("application/x-lexical-editor");if(r)try{const e=JSON.parse(r);if(e.namespace===l._config.namespace&&Array.isArray(e.nodes)){return N(l,_(e.nodes),n)}}catch(e){}if(!(o&&"insertReplacementText"===o.inputType&&e.types.includes("text/plain"))){const o=e.getData("text/html");if(o)try{const e=(new DOMParser).parseFromString(o,"text/html");return N(l,t(l,e),n)}catch(e){}}const c=e.getData("text/plain")||e.getData("text/uri-list");if(null!=c)if(s(n)){const e=c.split(/(\r?\n|\t)/);""===e[e.length-1]&&e.pop();for(let t=0;t<e.length;t++){const n=i();if(s(n)){const l=e[t];"\n"===l||"\r\n"===l?n.insertParagraph():"\t"===l?n.insertNodes([a()]):n.insertText(l)}}}else n.insertRawText(c)}function N(e,t,n){e.dispatchCommand(c,{nodes:t,selection:n})||n.insertNodes(t)}function R(e,t,n,r=[]){let i=null===t||n.isSelected(t);const s=g(n)&&n.excludeFromCopy("html");let a=n;if(null!==t){let e=l(n);e=p(e)&&null!==t?o(t,e):e,a=e}const c=g(a)?a.getChildren():[],u=function(e){const t=e.exportJSON(),n=e.constructor;if(t.type!==n.getType()&&x(58,n.name),g(e)){const e=t.children;Array.isArray(e)||x(59,n.name)}return t}(a);if(p(a)){const e=a.__text;e.length>0?u.text=e:i=!1}for(let l=0;l<c.length;l++){const o=c[l],r=R(e,t,o,u.children);!i&&g(n)&&r&&n.extractWithChild(o,t,"clone")&&(i=!0)}if(i&&!s)r.push(u);else if(Array.isArray(u.children))for(let e=0;e<u.children.length;e++){const t=u.children[e];r.push(t)}return i}function S(e,t){const n=[],l=u().getChildren();for(let o=0;o<l.length;o++){R(e,t,l[o],n)}return{namespace:e._config.namespace,nodes:n}}function _(e){const t=[];for(let l=0;l<e.length;l++){const o=e[l],r=d(o);p(r)&&n(r),t.push(r)}return t}let A=null;async function E(e,t){if(null!==A)return!1;if(null!==t)return new Promise(((n,l)=>{e.update((()=>{n(P(e,t))}))}));const n=e.getRootElement(),l=null==e._window?window.document:e._window.document,o=y(e._window);if(null===n||null===o)return!1;const i=l.createElement("span");i.style.cssText="position: fixed; top: -1000px;",i.append(l.createTextNode("#")),n.append(i);const s=new Range;return s.setStart(i,0),s.setEnd(i,1),o.removeAllRanges(),o.addRange(s),new Promise(((t,n)=>{const o=e.registerCommand(f,(n=>(r(n,ClipboardEvent)&&(o(),null!==A&&(window.clearTimeout(A),A=null),t(P(e,n))),!0)),m);A=window.setTimeout((()=>{o(),A=null,t(!1)}),50),l.execCommand("copy"),i.remove()}))}function P(e,t){const n=y(e._window);if(!n)return!1;const l=n.anchorNode,o=n.focusNode;if(null!==l&&null!==o&&!h(e,l,o))return!1;t.preventDefault();const r=t.clipboardData,s=i();if(null===r||null===s)return!1;const a=v(e),c=D(e);let u="";return null!==s&&(u=s.getTextContent()),null!==a&&r.setData("text/html",a),null!==c&&r.setData("application/x-lexical-editor",c),r.setData("text/plain",u),!0}export{S as $generateJSONFromSelectedNodes,_ as $generateNodesFromSerializedNodes,v as $getHtmlContent,D as $getLexicalContent,C as $insertDataTransferForPlainText,T as $insertDataTransferForRichText,N as $insertGeneratedNodes,E as copyToClipboard};
diff --git a/clipboard.d.ts b/clipboard.d.ts
index 99e2138389b64d298a1330d7b354ba87d2e6f24e..83250a4c2049f94e08bfdfc757e03e8a85a08dd4 100644
--- a/clipboard.d.ts
+++ b/clipboard.d.ts
@@ -44,7 +44,7 @@ export declare function $insertDataTransferForPlainText(dataTransfer: DataTransf
* @param selection the selection to use as the insertion point for the content in the DataTransfer object
* @param editor the LexicalEditor the content is being inserted into.
*/
-export declare function $insertDataTransferForRichText(dataTransfer: DataTransfer, selection: BaseSelection, editor: LexicalEditor): void;
+export declare function $insertDataTransferForRichText(dataTransfer: DataTransfer, selection: BaseSelection, editor: LexicalEditor, event?: InputEvent): void;
/**
* Inserts Lexical nodes into the editor using different strategies depending on
* some simple selection-based heuristics. If you're looking for a generic way to

View file

@ -0,0 +1,134 @@
diff --git a/LexicalClipboard.dev.js b/LexicalClipboard.dev.js
index 1bc958d606217588101f79ed3706669bb6b398ec..5c4e967e31d660504d41466b62e87449d4925ed2 100644
--- a/LexicalClipboard.dev.js
+++ b/LexicalClipboard.dev.js
@@ -93,7 +93,7 @@ function $insertDataTransferForPlainText(dataTransfer, selection) {
* @param selection the selection to use as the insertion point for the content in the DataTransfer object
* @param editor the LexicalEditor the content is being inserted into.
*/
-function $insertDataTransferForRichText(dataTransfer, selection, editor) {
+function $insertDataTransferForRichText(dataTransfer, selection, editor, event) {
const lexicalString = dataTransfer.getData('application/x-lexical-editor');
if (lexicalString) {
try {
@@ -106,15 +106,18 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) {
// Fail silently.
}
}
- const htmlString = dataTransfer.getData('text/html');
- if (htmlString) {
- try {
- const parser = new DOMParser();
- const dom = parser.parseFromString(trustHTML(htmlString), 'text/html');
- const nodes = html.$generateNodesFromDOM(editor, dom);
- return $insertGeneratedNodes(editor, nodes, selection);
- } catch (_unused2) {
- // Fail silently.
+ const shouldIgnoreHTML = event && event.inputType === 'insertReplacementText' && dataTransfer.types.includes('text/plain');
+ if (!shouldIgnoreHTML) {
+ const htmlString = dataTransfer.getData('text/html');
+ if (htmlString) {
+ try {
+ const parser = new DOMParser();
+ const dom = parser.parseFromString(trustHTML(htmlString), 'text/html');
+ const nodes = html.$generateNodesFromDOM(editor, dom);
+ return $insertGeneratedNodes(editor, nodes, selection);
+ } catch (_unused2) {
+ // Fail silently.
+ }
}
}
diff --git a/LexicalClipboard.dev.mjs b/LexicalClipboard.dev.mjs
index fd0c1b790dae92b742d569d62752d2c0b5705236..d00179beebd5d9f396fc3f7ab84745eea8959633 100644
--- a/LexicalClipboard.dev.mjs
+++ b/LexicalClipboard.dev.mjs
@@ -91,7 +91,7 @@ function $insertDataTransferForPlainText(dataTransfer, selection) {
* @param selection the selection to use as the insertion point for the content in the DataTransfer object
* @param editor the LexicalEditor the content is being inserted into.
*/
-function $insertDataTransferForRichText(dataTransfer, selection, editor) {
+function $insertDataTransferForRichText(dataTransfer, selection, editor, event) {
const lexicalString = dataTransfer.getData('application/x-lexical-editor');
if (lexicalString) {
try {
@@ -104,15 +104,18 @@ function $insertDataTransferForRichText(dataTransfer, selection, editor) {
// Fail silently.
}
}
- const htmlString = dataTransfer.getData('text/html');
- if (htmlString) {
- try {
- const parser = new DOMParser();
- const dom = parser.parseFromString(trustHTML(htmlString), 'text/html');
- const nodes = $generateNodesFromDOM(editor, dom);
- return $insertGeneratedNodes(editor, nodes, selection);
- } catch (_unused2) {
- // Fail silently.
+ const shouldIgnoreHTML = event && event.inputType === 'insertReplacementText' && dataTransfer.types.includes('text/plain');
+ if (!shouldIgnoreHTML) {
+ const htmlString = dataTransfer.getData('text/html');
+ if (htmlString) {
+ try {
+ const parser = new DOMParser();
+ const dom = parser.parseFromString(trustHTML(htmlString), 'text/html');
+ const nodes = $generateNodesFromDOM(editor, dom);
+ return $insertGeneratedNodes(editor, nodes, selection);
+ } catch (_unused2) {
+ // Fail silently.
+ }
}
}
diff --git a/LexicalClipboard.prod.js b/LexicalClipboard.prod.js
index da19707c8c6cfebbfbf4eab94eb4427e81015e01..afe044183dfe347f4da04277e1dd484ad11052fe 100644
--- a/LexicalClipboard.prod.js
+++ b/LexicalClipboard.prod.js
@@ -6,15 +6,15 @@
*
*/
-'use strict';var e=require("@lexical/html"),m=require("@lexical/selection"),n=require("@lexical/utils"),p=require("lexical"),t;function u(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}
-t=u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u["default"]:u;function v(a,b=p.$getSelection()){null==b&&t(166);return p.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?"":e.$generateHtmlFromNodes(a,b)}function w(a,b=p.$getSelection()){null==b&&t(166);return p.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?null:JSON.stringify(x(a,b))}
+'use strict';var f=require("@lexical/html"),m=require("@lexical/selection"),n=require("@lexical/utils"),p=require("lexical"),t;function u(a){let b=new URLSearchParams;b.append("code",a);for(let c=1;c<arguments.length;c++)b.append("v",arguments[c]);throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?${b} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}
+t=u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u["default"]:u;function v(a,b=p.$getSelection()){null==b&&t(166);return p.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?"":f.$generateHtmlFromNodes(a,b)}function w(a,b=p.$getSelection()){null==b&&t(166);return p.$isRangeSelection(b)&&b.isCollapsed()||0===b.getNodes().length?null:JSON.stringify(x(a,b))}
function y(a){return window.trustedTypes&&window.trustedTypes.createPolicy?window.trustedTypes.createPolicy("lexical",{createHTML:b=>b}).createHTML(a):a}function z(a,b,c){a.dispatchCommand(p.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND,{nodes:b,selection:c})||c.insertNodes(b)}
-function A(a,b,c,d=[]){let f=null!==b?c.isSelected(b):!0,k=p.$isElementNode(c)&&c.excludeFromCopy("html");var g=c;if(null!==b){var h=p.$cloneWithProperties(c);g=h=p.$isTextNode(h)&&null!==b?m.$sliceSelectedTextNodeContent(b,h):h}let q=p.$isElementNode(g)?g.getChildren():[];var l=g;h=l.exportJSON();var r=l.constructor;h.type!==r.getType()&&t(58,r.name);p.$isElementNode(l)&&(Array.isArray(h.children)||t(59,r.name));p.$isTextNode(g)&&(g=g.__text,0<g.length?h.text=g:f=!1);for(g=0;g<q.length;g++)l=q[g],
-r=A(a,b,l,h.children),!f&&p.$isElementNode(c)&&r&&c.extractWithChild(l,b,"clone")&&(f=!0);if(f&&!k)d.push(h);else if(Array.isArray(h.children))for(a=0;a<h.children.length;a++)d.push(h.children[a]);return f}function x(a,b){let c=[],d=p.$getRoot().getChildren();for(let f=0;f<d.length;f++)A(a,b,d[f],c);return{namespace:a._config.namespace,nodes:c}}function B(a){let b=[];for(let c=0;c<a.length;c++){let d=p.$parseSerializedNode(a[c]);p.$isTextNode(d)&&m.$addNodeStyle(d);b.push(d)}return b}let C=null;
+function A(a,b,c,d=[]){let h=null!==b?c.isSelected(b):!0,k=p.$isElementNode(c)&&c.excludeFromCopy("html");var e=c;if(null!==b){var g=p.$cloneWithProperties(c);e=g=p.$isTextNode(g)&&null!==b?m.$sliceSelectedTextNodeContent(b,g):g}let q=p.$isElementNode(e)?e.getChildren():[];var l=e;g=l.exportJSON();var r=l.constructor;g.type!==r.getType()&&t(58,r.name);p.$isElementNode(l)&&(Array.isArray(g.children)||t(59,r.name));p.$isTextNode(e)&&(e=e.__text,0<e.length?g.text=e:h=!1);for(e=0;e<q.length;e++)l=q[e],
+r=A(a,b,l,g.children),!h&&p.$isElementNode(c)&&r&&c.extractWithChild(l,b,"clone")&&(h=!0);if(h&&!k)d.push(g);else if(Array.isArray(g.children))for(a=0;a<g.children.length;a++)d.push(g.children[a]);return h}function x(a,b){let c=[],d=p.$getRoot().getChildren();for(let h=0;h<d.length;h++)A(a,b,d[h],c);return{namespace:a._config.namespace,nodes:c}}function B(a){let b=[];for(let c=0;c<a.length;c++){let d=p.$parseSerializedNode(a[c]);p.$isTextNode(d)&&m.$addNodeStyle(d);b.push(d)}return b}let C=null;
function D(a,b,c){if(void 0===c){var d=p.getDOMSelection(a._window);if(!d)return!1;c=d.anchorNode;d=d.focusNode;if(null!==c&&null!==d&&!p.isSelectionWithinEditor(a,c,d))return!1;a=p.$getSelection();if(null===a)return!1;c=E(a)}b.preventDefault();b=b.clipboardData;if(null===b)return!1;F(b,c);return!0}let G=[["text/html",v],["application/x-lexical-editor",w]];
-function E(a=p.$getSelection()){let b={"text/plain":a?a.getTextContent():""};if(a){let c=p.$getEditor();for(let [d,f]of G){let k=f(c,a);null!==k&&(b[d]=k)}}return b}function F(a,b){for(let c in b){let d=b[c];void 0!==d&&a.setData(c,d)}}exports.$generateJSONFromSelectedNodes=x;exports.$generateNodesFromSerializedNodes=B;exports.$getClipboardDataFromSelection=E;exports.$getHtmlContent=v;exports.$getLexicalContent=w;
+function E(a=p.$getSelection()){let b={"text/plain":a?a.getTextContent():""};if(a){let c=p.$getEditor();for(let [d,h]of G){let k=h(c,a);null!==k&&(b[d]=k)}}return b}function F(a,b){for(let c in b){let d=b[c];void 0!==d&&a.setData(c,d)}}exports.$generateJSONFromSelectedNodes=x;exports.$generateNodesFromSerializedNodes=B;exports.$getClipboardDataFromSelection=E;exports.$getHtmlContent=v;exports.$getLexicalContent=w;
exports.$insertDataTransferForPlainText=function(a,b){a=a.getData("text/plain")||a.getData("text/uri-list");null!=a&&b.insertRawText(a)};
-exports.$insertDataTransferForRichText=function(a,b,c){var d=a.getData("application/x-lexical-editor");if(d)try{let k=JSON.parse(d);if(k.namespace===c._config.namespace&&Array.isArray(k.nodes)){let g=B(k.nodes);return z(c,g,b)}}catch(k){}if(d=a.getData("text/html"))try{var f=(new DOMParser).parseFromString(y(d),"text/html");let k=e.$generateNodesFromDOM(c,f);return z(c,k,b)}catch(k){}a=a.getData("text/plain")||a.getData("text/uri-list");if(null!=a)if(p.$isRangeSelection(b))for(b=a.split(/(\r?\n|\t)/),
-""===b[b.length-1]&&b.pop(),a=0;a<b.length;a++)c=p.$getSelection(),p.$isRangeSelection(c)&&(f=b[a],"\n"===f||"\r\n"===f?c.insertParagraph():"\t"===f?c.insertNodes([p.$createTabNode()]):c.insertText(f));else b.insertRawText(a)};exports.$insertGeneratedNodes=z;
-exports.copyToClipboard=async function(a,b,c){if(null!==C)return!1;if(null!==b)return new Promise(h=>{a.update(()=>{h(D(a,b,c))})});var d=a.getRootElement();let f=null==a._window?window.document:a._window.document,k=p.getDOMSelection(a._window);if(null===d||null===k)return!1;let g=f.createElement("span");g.style.cssText="position: fixed; top: -1000px;";g.append(f.createTextNode("#"));d.append(g);d=new Range;d.setStart(g,0);d.setEnd(g,1);k.removeAllRanges();k.addRange(d);return new Promise(h=>{let q=
-a.registerCommand(p.COPY_COMMAND,l=>{n.objectKlassEquals(l,ClipboardEvent)&&(q(),null!==C&&(window.clearTimeout(C),C=null),h(D(a,l,c)));return!0},p.COMMAND_PRIORITY_CRITICAL);C=window.setTimeout(()=>{q();C=null;h(!1)},50);f.execCommand("copy");g.remove()})};exports.setLexicalClipboardDataTransfer=F
+exports.$insertDataTransferForRichText=function(a,b,c,d){let h=a.getData("application/x-lexical-editor");if(h)try{let e=JSON.parse(h);if(e.namespace===c._config.namespace&&Array.isArray(e.nodes)){let g=B(e.nodes);return z(c,g,b)}}catch(e){}if(!d||"insertReplacementText"!==d.inputType||!a.types.includes("text/plain"))if(d=a.getData("text/html"))try{var k=(new DOMParser).parseFromString(y(d),"text/html");let e=f.$generateNodesFromDOM(c,k);return z(c,e,b)}catch(e){}a=a.getData("text/plain")||a.getData("text/uri-list");
+if(null!=a)if(p.$isRangeSelection(b))for(b=a.split(/(\r?\n|\t)/),""===b[b.length-1]&&b.pop(),a=0;a<b.length;a++)c=p.$getSelection(),p.$isRangeSelection(c)&&(k=b[a],"\n"===k||"\r\n"===k?c.insertParagraph():"\t"===k?c.insertNodes([p.$createTabNode()]):c.insertText(k));else b.insertRawText(a)};exports.$insertGeneratedNodes=z;
+exports.copyToClipboard=async function(a,b,c){if(null!==C)return!1;if(null!==b)return new Promise(g=>{a.update(()=>{g(D(a,b,c))})});var d=a.getRootElement();let h=null==a._window?window.document:a._window.document,k=p.getDOMSelection(a._window);if(null===d||null===k)return!1;let e=h.createElement("span");e.style.cssText="position: fixed; top: -1000px;";e.append(h.createTextNode("#"));d.append(e);d=new Range;d.setStart(e,0);d.setEnd(e,1);k.removeAllRanges();k.addRange(d);return new Promise(g=>{let q=
+a.registerCommand(p.COPY_COMMAND,l=>{n.objectKlassEquals(l,ClipboardEvent)&&(q(),null!==C&&(window.clearTimeout(C),C=null),g(D(a,l,c)));return!0},p.COMMAND_PRIORITY_CRITICAL);C=window.setTimeout(()=>{q();C=null;g(!1)},50);h.execCommand("copy");e.remove()})};exports.setLexicalClipboardDataTransfer=F
diff --git a/LexicalClipboard.prod.mjs b/LexicalClipboard.prod.mjs
index 0a2b0694926fa9838a417295956bc832a02d5499..68090dd340db822053b4e3ceda8f68e4413c8908 100644
--- a/LexicalClipboard.prod.mjs
+++ b/LexicalClipboard.prod.mjs
@@ -6,4 +6,4 @@
*
*/
-import{$generateHtmlFromNodes as t,$generateNodesFromDOM as e}from"@lexical/html";import{$addNodeStyle as n,$sliceSelectedTextNodeContent as o}from"@lexical/selection";import{objectKlassEquals as r}from"@lexical/utils";import{$isRangeSelection as l,$getSelection as i,$createTabNode as s,SELECTION_INSERT_CLIPBOARD_NODES_COMMAND as c,$getRoot as a,$parseSerializedNode as u,$isTextNode as d,getDOMSelection as f,COPY_COMMAND as p,COMMAND_PRIORITY_CRITICAL as m,isSelectionWithinEditor as h,$getEditor as g,$isElementNode as x,$cloneWithProperties as w}from"lexical";function y(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var T=y((function(t){const e=new URLSearchParams;e.append("code",t);for(let t=1;t<arguments.length;t++)e.append("v",arguments[t]);throw Error(`Minified Lexical error #${t}; visit https://lexical.dev/docs/error?${e} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));function v(e,n=i()){return null==n&&T(166),l(n)&&n.isCollapsed()||0===n.getNodes().length?"":t(e,n)}function C(t,e=i()){return null==e&&T(166),l(e)&&e.isCollapsed()||0===e.getNodes().length?null:JSON.stringify(A(t,e))}function D(t,e){const n=t.getData("text/plain")||t.getData("text/uri-list");null!=n&&e.insertRawText(n)}function N(t,n,o){const r=t.getData("application/x-lexical-editor");if(r)try{const t=JSON.parse(r);if(t.namespace===o._config.namespace&&Array.isArray(t.nodes)){return _(o,R(t.nodes),n)}}catch(t){}const c=t.getData("text/html");if(c)try{const t=(new DOMParser).parseFromString(function(t){if(window.trustedTypes&&window.trustedTypes.createPolicy){return window.trustedTypes.createPolicy("lexical",{createHTML:t=>t}).createHTML(t)}return t}(c),"text/html");return _(o,e(o,t),n)}catch(t){}const a=t.getData("text/plain")||t.getData("text/uri-list");if(null!=a)if(l(n)){const t=a.split(/(\r?\n|\t)/);""===t[t.length-1]&&t.pop();for(let e=0;e<t.length;e++){const n=i();if(l(n)){const o=t[e];"\n"===o||"\r\n"===o?n.insertParagraph():"\t"===o?n.insertNodes([s()]):n.insertText(o)}}}else n.insertRawText(a)}function _(t,e,n){t.dispatchCommand(c,{nodes:e,selection:n})||n.insertNodes(e)}function P(t,e,n,r=[]){let l=null===e||n.isSelected(e);const i=x(n)&&n.excludeFromCopy("html");let s=n;if(null!==e){let t=w(n);t=d(t)&&null!==e?o(e,t):t,s=t}const c=x(s)?s.getChildren():[],a=function(t){const e=t.exportJSON(),n=t.constructor;if(e.type!==n.getType()&&T(58,n.name),x(t)){const t=e.children;Array.isArray(t)||T(59,n.name)}return e}(s);if(d(s)){const t=s.__text;t.length>0?a.text=t:l=!1}for(let o=0;o<c.length;o++){const r=c[o],i=P(t,e,r,a.children);!l&&x(n)&&i&&n.extractWithChild(r,e,"clone")&&(l=!0)}if(l&&!i)r.push(a);else if(Array.isArray(a.children))for(let t=0;t<a.children.length;t++){const e=a.children[t];r.push(e)}return l}function A(t,e){const n=[],o=a().getChildren();for(let r=0;r<o.length;r++){P(t,e,o[r],n)}return{namespace:t._config.namespace,nodes:n}}function R(t){const e=[];for(let o=0;o<t.length;o++){const r=t[o],l=u(r);d(l)&&n(l),e.push(l)}return e}let S=null;async function O(t,e,n){if(null!==S)return!1;if(null!==e)return new Promise(((o,r)=>{t.update((()=>{o(E(t,e,n))}))}));const o=t.getRootElement(),l=null==t._window?window.document:t._window.document,i=f(t._window);if(null===o||null===i)return!1;const s=l.createElement("span");s.style.cssText="position: fixed; top: -1000px;",s.append(l.createTextNode("#")),o.append(s);const c=new Range;return c.setStart(s,0),c.setEnd(s,1),i.removeAllRanges(),i.addRange(c),new Promise(((e,o)=>{const i=t.registerCommand(p,(o=>(r(o,ClipboardEvent)&&(i(),null!==S&&(window.clearTimeout(S),S=null),e(E(t,o,n))),!0)),m);S=window.setTimeout((()=>{i(),S=null,e(!1)}),50),l.execCommand("copy"),s.remove()}))}function E(t,e,n){if(void 0===n){const e=f(t._window);if(!e)return!1;const o=e.anchorNode,r=e.focusNode;if(null!==o&&null!==r&&!h(t,o,r))return!1;const l=i();if(null===l)return!1;n=L(l)}e.preventDefault();const o=e.clipboardData;return null!==o&&(b(o,n),!0)}const M=[["text/html",v],["application/x-lexical-editor",C]];function L(t=i()){const e={"text/plain":t?t.getTextContent():""};if(t){const n=g();for(const[o,r]of M){const l=r(n,t);null!==l&&(e[o]=l)}}return e}function b(t,e){for(const n in e){const o=e[n];void 0!==o&&t.setData(n,o)}}export{A as $generateJSONFromSelectedNodes,R as $generateNodesFromSerializedNodes,L as $getClipboardDataFromSelection,v as $getHtmlContent,C as $getLexicalContent,D as $insertDataTransferForPlainText,N as $insertDataTransferForRichText,_ as $insertGeneratedNodes,O as copyToClipboard,b as setLexicalClipboardDataTransfer};
+import{$generateHtmlFromNodes as t,$generateNodesFromDOM as e}from"@lexical/html";import{$addNodeStyle as n,$sliceSelectedTextNodeContent as o}from"@lexical/selection";import{objectKlassEquals as r}from"@lexical/utils";import{$isRangeSelection as l,$getSelection as i,$createTabNode as s,SELECTION_INSERT_CLIPBOARD_NODES_COMMAND as c,$getRoot as a,$parseSerializedNode as u,$isTextNode as d,getDOMSelection as f,COPY_COMMAND as p,COMMAND_PRIORITY_CRITICAL as m,isSelectionWithinEditor as h,$getEditor as x,$isElementNode as g,$cloneWithProperties as w}from"lexical";function y(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var T=y((function(t){const e=new URLSearchParams;e.append("code",t);for(let t=1;t<arguments.length;t++)e.append("v",arguments[t]);throw Error(`Minified Lexical error #${t}; visit https://lexical.dev/docs/error?${e} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));function v(e,n=i()){return null==n&&T(166),l(n)&&n.isCollapsed()||0===n.getNodes().length?"":t(e,n)}function C(t,e=i()){return null==e&&T(166),l(e)&&e.isCollapsed()||0===e.getNodes().length?null:JSON.stringify(R(t,e))}function D(t,e){const n=t.getData("text/plain")||t.getData("text/uri-list");null!=n&&e.insertRawText(n)}function N(t,n,o,r){const c=t.getData("application/x-lexical-editor");if(c)try{const t=JSON.parse(c);if(t.namespace===o._config.namespace&&Array.isArray(t.nodes)){return _(o,A(t.nodes),n)}}catch(t){}if(!(r&&"insertReplacementText"===r.inputType&&t.types.includes("text/plain"))){const r=t.getData("text/html");if(r)try{const t=(new DOMParser).parseFromString(function(t){if(window.trustedTypes&&window.trustedTypes.createPolicy){return window.trustedTypes.createPolicy("lexical",{createHTML:t=>t}).createHTML(t)}return t}(r),"text/html");return _(o,e(o,t),n)}catch(t){}}const a=t.getData("text/plain")||t.getData("text/uri-list");if(null!=a)if(l(n)){const t=a.split(/(\r?\n|\t)/);""===t[t.length-1]&&t.pop();for(let e=0;e<t.length;e++){const n=i();if(l(n)){const o=t[e];"\n"===o||"\r\n"===o?n.insertParagraph():"\t"===o?n.insertNodes([s()]):n.insertText(o)}}}else n.insertRawText(a)}function _(t,e,n){t.dispatchCommand(c,{nodes:e,selection:n})||n.insertNodes(e)}function P(t,e,n,r=[]){let l=null===e||n.isSelected(e);const i=g(n)&&n.excludeFromCopy("html");let s=n;if(null!==e){let t=w(n);t=d(t)&&null!==e?o(e,t):t,s=t}const c=g(s)?s.getChildren():[],a=function(t){const e=t.exportJSON(),n=t.constructor;if(e.type!==n.getType()&&T(58,n.name),g(t)){const t=e.children;Array.isArray(t)||T(59,n.name)}return e}(s);if(d(s)){const t=s.__text;t.length>0?a.text=t:l=!1}for(let o=0;o<c.length;o++){const r=c[o],i=P(t,e,r,a.children);!l&&g(n)&&i&&n.extractWithChild(r,e,"clone")&&(l=!0)}if(l&&!i)r.push(a);else if(Array.isArray(a.children))for(let t=0;t<a.children.length;t++){const e=a.children[t];r.push(e)}return l}function R(t,e){const n=[],o=a().getChildren();for(let r=0;r<o.length;r++){P(t,e,o[r],n)}return{namespace:t._config.namespace,nodes:n}}function A(t){const e=[];for(let o=0;o<t.length;o++){const r=t[o],l=u(r);d(l)&&n(l),e.push(l)}return e}let S=null;async function O(t,e,n){if(null!==S)return!1;if(null!==e)return new Promise(((o,r)=>{t.update((()=>{o(E(t,e,n))}))}));const o=t.getRootElement(),l=null==t._window?window.document:t._window.document,i=f(t._window);if(null===o||null===i)return!1;const s=l.createElement("span");s.style.cssText="position: fixed; top: -1000px;",s.append(l.createTextNode("#")),o.append(s);const c=new Range;return c.setStart(s,0),c.setEnd(s,1),i.removeAllRanges(),i.addRange(c),new Promise(((e,o)=>{const i=t.registerCommand(p,(o=>(r(o,ClipboardEvent)&&(i(),null!==S&&(window.clearTimeout(S),S=null),e(E(t,o,n))),!0)),m);S=window.setTimeout((()=>{i(),S=null,e(!1)}),50),l.execCommand("copy"),s.remove()}))}function E(t,e,n){if(void 0===n){const e=f(t._window);if(!e)return!1;const o=e.anchorNode,r=e.focusNode;if(null!==o&&null!==r&&!h(t,o,r))return!1;const l=i();if(null===l)return!1;n=L(l)}e.preventDefault();const o=e.clipboardData;return null!==o&&(b(o,n),!0)}const M=[["text/html",v],["application/x-lexical-editor",C]];function L(t=i()){const e={"text/plain":t?t.getTextContent():""};if(t){const n=x();for(const[o,r]of M){const l=r(n,t);null!==l&&(e[o]=l)}}return e}function b(t,e){for(const n in e){const o=e[n];void 0!==o&&t.setData(n,o)}}export{R as $generateJSONFromSelectedNodes,A as $generateNodesFromSerializedNodes,L as $getClipboardDataFromSelection,v as $getHtmlContent,C as $getLexicalContent,D as $insertDataTransferForPlainText,N as $insertDataTransferForRichText,_ as $insertGeneratedNodes,O as copyToClipboard,b as setLexicalClipboardDataTransfer};
diff --git a/clipboard.d.ts b/clipboard.d.ts
index 33ee79d61150403f45566839251c5c2950fba8e0..b7a27d5f4700814f55bfc988eead2709e8f2a040 100644
--- a/clipboard.d.ts
+++ b/clipboard.d.ts
@@ -51,7 +51,7 @@ export declare function $insertDataTransferForPlainText(dataTransfer: DataTransf
* @param selection the selection to use as the insertion point for the content in the DataTransfer object
* @param editor the LexicalEditor the content is being inserted into.
*/
-export declare function $insertDataTransferForRichText(dataTransfer: DataTransfer, selection: BaseSelection, editor: LexicalEditor): void;
+export declare function $insertDataTransferForRichText(dataTransfer: DataTransfer, selection: BaseSelection, editor: LexicalEditor, event?: InputEvent): void;
/**
* Inserts Lexical nodes into the editor using different strategies depending on
* some simple selection-based heuristics. If you're looking for a generic way to

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -44,9 +44,8 @@
"@types/react-native-vector-icons/@types/react": "17.0.2",
"@types/react-native/@types/react": "17.0.2",
"@types/hoist-non-react-statics/@types/react": "17.0.2",
"@lexical/clipboard@0.16.0": "patch:@lexical/clipboard@npm:0.16.0#.yarn/patches/@lexical-clipboard-npm-0.16.0-3053c4af9c.patch",
"@lexical/rich-text@0.16.0": "patch:@lexical/rich-text@npm:0.16.0#.yarn/patches/@lexical-rich-text-npm-0.16.0-f484a17832.patch",
"@lexical/list@0.16.0": "patch:@lexical/list@npm:0.16.0#.yarn/patches/@lexical-list-npm-0.16.0-8f91da4ad5.patch"
"@lexical/clipboard@0.22.0": "patch:@lexical/clipboard@npm:0.22.0#.yarn/patches/@lexical-clipboard-npm-0.22.0-e950aa6a7f.patch",
"@lexical/rich-text@0.22.0": "patch:@lexical/rich-text@npm:0.22.0#.yarn/patches/@lexical-rich-text-npm-0.22.0-1c32cc4b16.patch"
},
"dependencies": {
"@standardnotes/snjs": "workspace:*"

View file

@ -1800,10 +1800,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
boost: 4cb898d0bf20404aab1850c656dcea009429d6c1
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
FBLazyVector: 7b438dceb9f904bd85ca3c31d64cce32a035472b
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
hermes-engine: 8d2103d6c0176779aea4e25df6bb1410f9946680
MMKV: 817ba1eea17421547e01e087285606eb270a8dcb
MMKVCore: af055b00e27d88cd92fad301c5fecd1ff9b26dd9

View file

@ -107,17 +107,17 @@
},
"dependencies": {
"@ariakit/react": "^0.3.9",
"@lexical/clipboard": "0.16.0",
"@lexical/headless": "0.16.0",
"@lexical/link": "0.16.0",
"@lexical/list": "0.16.0",
"@lexical/react": "0.16.0",
"@lexical/rich-text": "0.16.0",
"@lexical/utils": "0.16.0",
"@lexical/clipboard": "0.22.0",
"@lexical/headless": "0.22.0",
"@lexical/link": "0.22.0",
"@lexical/list": "0.22.0",
"@lexical/react": "0.22.0",
"@lexical/rich-text": "0.22.0",
"@lexical/utils": "0.22.0",
"@radix-ui/react-slot": "^1.0.1",
"@react-pdf/renderer": "^3.3.2",
"comlink": "^4.4.1",
"fast-diff": "^1.3.0",
"lexical": "0.16.0"
"lexical": "0.22.0"
}
}

View file

@ -1,10 +1,11 @@
import { $createParagraphNode, $getRoot, $insertNodes, $nodesOfType, LexicalNode } from 'lexical'
import { $createParagraphNode, $getRoot, $insertNodes, LexicalNode } from 'lexical'
import { $generateNodesFromDOM } from '@lexical/html'
import { createHeadlessEditor } from '@lexical/headless'
import { BlockEditorNodes } from '../SuperEditor/Lexical/Nodes/AllNodes'
import BlocksEditorTheme from '../SuperEditor/Lexical/Theme/Theme'
import { ClipPayload } from '@standardnotes/clipper/src/types/message'
import { LinkNode } from '@lexical/link'
import { $isLinkNode } from '@lexical/link'
import { $dfs } from '@lexical/utils'
const AbsoluteLinkRegExp = new RegExp('^(?:[a-z+]+:)?//', 'i')
@ -66,15 +67,18 @@ export const getSuperJSONFromClipPayload = async (clipPayload: ClipPayload) => {
await new Promise<void>((resolve) => {
editor.update(() => {
$nodesOfType(LinkNode).forEach((linkNode) => {
const url = linkNode.getURL()
for (const { node } of $dfs()) {
if (!$isLinkNode(node)) {
continue
}
const url = node.getURL()
const isAbsoluteLink = AbsoluteLinkRegExp.test(url)
if (!isAbsoluteLink) {
const fixedURL = new URL(url, clipURL)
linkNode.setURL(fixedURL.toString())
node.setURL(fixedURL.toString())
}
})
}
resolve()
})

View file

@ -1,6 +1,6 @@
import { DecoratorBlockNode, SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode'
import { parseAndCreateZippableFileName } from '@standardnotes/utils'
import { DOMExportOutput, Spread } from 'lexical'
import { DOMExportOutput, ElementFormatType, NodeKey, Spread } from 'lexical'
type SerializedFileExportNode = Spread<
{
@ -20,14 +20,14 @@ export class FileExportNode extends DecoratorBlockNode {
return 'file-export'
}
constructor(name: string, mimeType: string) {
super()
constructor(name: string, mimeType: string, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__name = name
this.__mimeType = mimeType
}
static clone(node: FileExportNode): FileExportNode {
return new FileExportNode(node.__name, node.__mimeType)
return new FileExportNode(node.__name, node.__mimeType, node.__format, node.__key)
}
static importJSON(serializedNode: SerializedFileExportNode): FileExportNode {

View file

@ -127,6 +127,11 @@ export class TweetNode extends DecoratorBlockNode {
return 'tweet'
}
constructor(id: string, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__id = id
}
static override clone(node: TweetNode): TweetNode {
return new TweetNode(node.__id, node.__format, node.__key)
}
@ -168,11 +173,6 @@ export class TweetNode extends DecoratorBlockNode {
return { element }
}
constructor(id: string, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__id = id
}
getId(): string {
return this.__id
}

View file

@ -72,6 +72,11 @@ export class YouTubeNode extends DecoratorBlockNode {
return 'youtube'
}
constructor(id: string, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__id = id
}
static clone(node: YouTubeNode): YouTubeNode {
return new YouTubeNode(node.__id, node.__format, node.__key)
}
@ -121,11 +126,6 @@ export class YouTubeNode extends DecoratorBlockNode {
}
}
constructor(id: string, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__id = id
}
updateDOM(): false {
return false
}

View file

@ -7,12 +7,9 @@
*/
/**
* Taken from https://github.com/facebook/lexical/blob/main/packages/lexical-markdown/src/MarkdownExport.ts
* but modified using changes from https://github.com/facebook/lexical/pull/4957 to make nested elements work
* better when exporting to markdown.
*/
* Taken from https://github.com/facebook/lexical/blob/main/packages/lexical-markdown/src/MarkdownExport.ts but modified using changes from https://github.com/facebook/lexical/pull/4957 to make nested elements work better when exporting to markdown.
* */
import type { ElementTransformer, TextFormatTransformer, TextMatchTransformer, Transformer } from '@lexical/markdown'
import {
ElementNode,
LexicalNode,
@ -24,10 +21,27 @@ import {
$isLineBreakNode,
$isTextNode,
} from 'lexical'
import { TRANSFORMERS, transformersByType } from './MarkdownImportExportUtils'
export function createMarkdownExport(transformers: Array<Transformer>): (node?: ElementNode) => string {
import {
ElementTransformer,
MultilineElementTransformer,
TextFormatTransformer,
TextMatchTransformer,
Transformer,
} from '@lexical/markdown'
import { isEmptyParagraph, TRANSFORMERS, transformersByType } from './MarkdownImportExportUtils'
/**
* Renders string from markdown. The selection is moved to the start after the operation.
*/
function createMarkdownExport(
transformers: Array<Transformer>,
shouldPreserveNewLines: boolean = false,
): (node?: ElementNode) => string {
const byType = transformersByType(transformers)
const elementTransformers = [...byType.multilineElement, ...byType.element]
const isNewlineDelimited = !shouldPreserveNewLines
// Export only uses text formats that are responsible for single format
// e.g. it will filter out *** (bold, italic) and instead use separate ** and *
@ -37,25 +51,35 @@ export function createMarkdownExport(transformers: Array<Transformer>): (node?:
const output = []
const children = (node || $getRoot()).getChildren()
for (const child of children) {
const result = exportTopLevelElements(child, byType.element, textFormatTransformers, byType.textMatch)
for (let i = 0; i < children.length; i++) {
const child = children[i]
const result = exportTopLevelElements(child, elementTransformers, textFormatTransformers, byType.textMatch)
if (result != null) {
output.push(result)
output.push(
// separate consecutive group of texts with a line break: eg. ["hello", "world"] -> ["hello", "/nworld"]
isNewlineDelimited && i > 0 && !isEmptyParagraph(child) && !isEmptyParagraph(children[i - 1])
? '\n'.concat(result)
: result,
)
}
}
return output.join('\n\n')
// Ensure consecutive groups of texts are at least \n\n apart while each empty paragraph render as a newline.
// Eg. ["hello", "", "", "hi", "\nworld"] -> "hello\n\n\nhi\n\nworld"
return output.join('\n')
}
}
function exportTopLevelElements(
node: LexicalNode,
elementTransformers: Array<ElementTransformer>,
elementTransformers: Array<ElementTransformer | MultilineElementTransformer>,
textTransformersIndex: Array<TextFormatTransformer>,
textMatchTransformers: Array<TextMatchTransformer>,
): string | null {
for (const transformer of elementTransformers) {
if (!transformer.export) {
continue
}
const result = transformer.export(node, (_node) =>
exportChildren(_node, elementTransformers, textTransformersIndex, textMatchTransformers),
)
@ -76,23 +100,33 @@ function exportTopLevelElements(
function exportChildren(
node: ElementNode,
elementTransformers: Array<ElementTransformer>,
elementTransformers: Array<ElementTransformer | MultilineElementTransformer>,
textTransformersIndex: Array<TextFormatTransformer>,
textMatchTransformers: Array<TextMatchTransformer>,
): string {
const output = []
const children = node.getChildren()
const childrenLength = children.length
// keep track of unclosed tags from the very beginning
const unclosedTags: { format: TextFormatType; tag: string }[] = []
mainLoop: for (let childIndex = 0; childIndex < childrenLength; childIndex++) {
const child = children[childIndex]
const isLastChild = childIndex === childrenLength - 1
mainLoop: for (const child of children) {
if ($isElementNode(child)) {
for (const transformer of elementTransformers) {
if (!transformer.export) {
continue
}
const result = transformer.export(child, (_node) =>
exportChildren(_node, elementTransformers, textTransformersIndex, textMatchTransformers),
)
if (result != null) {
output.push(result)
if (children.indexOf(child) !== children.length - 1) {
if (!isLastChild) {
output.push('\n')
}
continue mainLoop
@ -101,10 +135,14 @@ function exportChildren(
}
for (const transformer of textMatchTransformers) {
if (!transformer.export) {
continue
}
const result = transformer.export(
child,
(parentNode) => exportChildren(parentNode, elementTransformers, textTransformersIndex, textMatchTransformers),
(textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex),
(textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex, unclosedTags),
)
if (result != null) {
@ -116,9 +154,15 @@ function exportChildren(
if ($isLineBreakNode(child)) {
output.push('\n')
} else if ($isTextNode(child)) {
output.push(exportTextFormat(child, child.getTextContent(), textTransformersIndex))
output.push(exportTextFormat(child, child.getTextContent(), textTransformersIndex, unclosedTags))
} else if ($isElementNode(child)) {
output.push(exportChildren(child, elementTransformers, textTransformersIndex, textMatchTransformers), '\n')
// empty paragraph returns ""
output.push(exportChildren(child, elementTransformers, textTransformersIndex, textMatchTransformers))
// Don't insert linebreak after last child
if (!isLastChild) {
// Insert two line breaks to create a space between two paragraphs or other elements, as required by Markdown syntax.
output.push('\n', '\n')
}
} else if ($isDecoratorNode(child)) {
output.push(child.getTextContent())
}
@ -127,13 +171,26 @@ function exportChildren(
return output.join('')
}
function exportTextFormat(node: TextNode, textContent: string, textTransformers: Array<TextFormatTransformer>): string {
function exportTextFormat(
node: TextNode,
textContent: string,
textTransformers: Array<TextFormatTransformer>,
// unclosed tags include the markdown tags that haven't been closed yet, and their associated formats
unclosedTags: Array<{ format: TextFormatType; tag: string }>,
): string {
// This function handles the case of a string looking like this: " foo "
// Where it would be invalid markdown to generate: "** foo **"
// We instead want to trim the whitespace out, apply formatting, and then
// bring the whitespace back. So our returned string looks like this: " **foo** "
const frozenString = textContent.trim()
let output = frozenString
// the opening tags to be added to the result
let openingTags = ''
// the closing tags to be added to the result
let closingTags = ''
const prevNode = getTextSibling(node, true)
const nextNode = getTextSibling(node, false)
const applied = new Set()
@ -141,27 +198,39 @@ function exportTextFormat(node: TextNode, textContent: string, textTransformers:
const format = transformer.format[0]
const tag = transformer.tag
// dedup applied formats
if (hasFormat(node, format) && !applied.has(format)) {
// Multiple tags might be used for the same format (*, _)
applied.add(format)
// Prevent adding opening tag is already opened by the previous sibling
const previousNode = getTextSibling(node, true)
if (!hasFormat(previousNode, format)) {
output = tag + output
}
// Prevent adding closing tag if next sibling will do it
const nextNode = getTextSibling(node, false)
if (!hasFormat(nextNode, format)) {
output += tag
// append the tag to openningTags, if it's not applied to the previous nodes,
// or the nodes before that (which would result in an unclosed tag)
if (!hasFormat(prevNode, format) || !unclosedTags.find((element) => element.tag === tag)) {
unclosedTags.push({ format, tag })
openingTags += tag
}
}
}
// close any tags in the same order they were applied, if necessary
for (let i = 0; i < unclosedTags.length; i++) {
// prevent adding closing tag if next sibling will do it
if (hasFormat(nextNode, unclosedTags[i].format)) {
continue
}
while (unclosedTags.length > i) {
const unclosedTag = unclosedTags.pop()
if (unclosedTag && typeof unclosedTag.tag === 'string') {
closingTags += unclosedTag.tag
}
}
break
}
output = openingTags + output + closingTags
// Replace trimmed version of textContent ensuring surrounding whitespace is not modified
return textContent.replace(frozenString, output)
return textContent.replace(frozenString, () => output)
}
// Get next or previous text sibling a text node, including cases
@ -208,7 +277,11 @@ function hasFormat(node: LexicalNode | null | undefined, format: TextFormatType)
return $isTextNode(node) && node.hasFormat(format)
}
export function $convertToMarkdownString(transformers: Array<Transformer> = TRANSFORMERS, node?: ElementNode): string {
const exportMarkdown = createMarkdownExport(transformers)
export function $convertToMarkdownString(
transformers: Array<Transformer> = TRANSFORMERS,
node?: ElementNode,
shouldPreserveNewLines: boolean = false,
): string {
const exportMarkdown = createMarkdownExport(transformers, shouldPreserveNewLines)
return exportMarkdown(node)
}

View file

@ -1,368 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
/**
* Taken from https://github.com/facebook/lexical/blob/main/packages/lexical-markdown/src/MarkdownImport.ts
* but modified to allow keeping new lines when importing markdown.
*/
import { CodeNode, $createCodeNode } from '@lexical/code'
import { ElementTransformer, TextFormatTransformer, TextMatchTransformer, Transformer } from '@lexical/markdown'
import { $isListItemNode, $isListNode, ListItemNode } from '@lexical/list'
import { $isQuoteNode } from '@lexical/rich-text'
import { $findMatchingParent } from '@lexical/utils'
import {
LexicalNode,
TextNode,
$createLineBreakNode,
$createParagraphNode,
$createTextNode,
$getRoot,
$getSelection,
$isParagraphNode,
$isTextNode,
ElementNode,
} from 'lexical'
import { IS_APPLE_WEBKIT, IS_IOS, IS_SAFARI } from '../Shared/environment'
import { TRANSFORMERS, transformersByType } from './MarkdownImportExportUtils'
const PUNCTUATION_OR_SPACE = /[!-/:-@[-`{-~\s]/
const MARKDOWN_EMPTY_LINE_REG_EXP = /^\s{0,3}$/
const CODE_BLOCK_REG_EXP = /^```(\w{1,10})?\s?$/
type TextFormatTransformersIndex = Readonly<{
fullMatchRegExpByTag: Readonly<Record<string, RegExp>>
openTagsRegExp: RegExp
transformersByTag: Readonly<Record<string, TextFormatTransformer>>
}>
function createMarkdownImport(
transformers: Array<Transformer>,
): (markdownString: string, node?: ElementNode, keepNewLines?: boolean) => void {
const byType = transformersByType(transformers)
const textFormatTransformersIndex = createTextFormatTransformersIndex(byType.textFormat)
return (markdownString, node, keepNewLines = false) => {
const lines = markdownString.split('\n')
const linesLength = lines.length
const root = node || $getRoot()
root.clear()
for (let i = 0; i < linesLength; i++) {
const lineText = lines[i]
// Codeblocks are processed first as anything inside such block
// is ignored for further processing
// TODO:
// Abstract it to be dynamic as other transformers (add multiline match option)
const [codeBlockNode, shiftedIndex] = importCodeBlock(lines, i, root)
if (codeBlockNode != null) {
i = shiftedIndex
continue
}
importBlocks(lineText, root, byType.element, textFormatTransformersIndex, byType.textMatch)
}
if (!keepNewLines) {
// Removing empty paragraphs as md does not really
// allow empty lines and uses them as dilimiter
const children = root.getChildren()
for (const child of children) {
if (isEmptyParagraph(child)) {
child.remove()
}
}
}
if ($getSelection() !== null) {
root.selectEnd()
}
}
}
function isEmptyParagraph(node: LexicalNode): boolean {
if (!$isParagraphNode(node)) {
return false
}
const firstChild = node.getFirstChild()
return (
firstChild == null ||
(node.getChildrenSize() === 1 &&
$isTextNode(firstChild) &&
MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent()))
)
}
function importBlocks(
lineText: string,
rootNode: ElementNode,
elementTransformers: Array<ElementTransformer>,
textFormatTransformersIndex: TextFormatTransformersIndex,
textMatchTransformers: Array<TextMatchTransformer>,
) {
const lineTextTrimmed = lineText.trim()
const textNode = $createTextNode(lineTextTrimmed)
const elementNode = $createParagraphNode()
elementNode.append(textNode)
rootNode.append(elementNode)
for (const { regExp, replace } of elementTransformers) {
const match = lineText.match(regExp)
if (match) {
textNode.setTextContent(lineText.slice(match[0].length))
replace(elementNode, [textNode], match, true)
break
}
}
importTextFormatTransformers(textNode, textFormatTransformersIndex, textMatchTransformers)
// If no transformer found and we left with original paragraph node
// can check if its content can be appended to the previous node
// if it's a paragraph, quote or list
if (elementNode.isAttached() && lineTextTrimmed.length > 0) {
const previousNode = elementNode.getPreviousSibling()
if ($isParagraphNode(previousNode) || $isQuoteNode(previousNode) || $isListNode(previousNode)) {
let targetNode: typeof previousNode | ListItemNode | null = previousNode
if ($isListNode(previousNode)) {
const lastDescendant = previousNode.getLastDescendant()
if (lastDescendant == null) {
targetNode = null
} else {
targetNode = $findMatchingParent(lastDescendant, $isListItemNode)
}
}
if (targetNode != null && targetNode.getTextContentSize() > 0) {
targetNode.splice(targetNode.getChildrenSize(), 0, [$createLineBreakNode(), ...elementNode.getChildren()])
elementNode.remove()
}
}
}
}
function importCodeBlock(
lines: Array<string>,
startLineIndex: number,
rootNode: ElementNode,
): [CodeNode | null, number] {
const openMatch = lines[startLineIndex].match(CODE_BLOCK_REG_EXP)
if (openMatch) {
let endLineIndex = startLineIndex
const linesLength = lines.length
while (++endLineIndex < linesLength) {
const closeMatch = lines[endLineIndex].match(CODE_BLOCK_REG_EXP)
if (closeMatch) {
const codeBlockNode = $createCodeNode(openMatch[1])
const textNode = $createTextNode(lines.slice(startLineIndex + 1, endLineIndex).join('\n'))
codeBlockNode.append(textNode)
rootNode.append(codeBlockNode)
return [codeBlockNode, endLineIndex]
}
}
}
return [null, startLineIndex]
}
// Processing text content and replaces text format tags.
// It takes outermost tag match and its content, creates text node with
// format based on tag and then recursively executed over node's content
//
// E.g. for "*Hello **world**!*" string it will create text node with
// "Hello **world**!" content and italic format and run recursively over
// its content to transform "**world**" part
function importTextFormatTransformers(
textNode: TextNode,
textFormatTransformersIndex: TextFormatTransformersIndex,
textMatchTransformers: Array<TextMatchTransformer>,
) {
const textContent = textNode.getTextContent()
const match = findOutermostMatch(textContent, textFormatTransformersIndex)
if (!match) {
// Once text format processing is done run text match transformers, as it
// only can span within single text node (unline formats that can cover multiple nodes)
importTextMatchTransformers(textNode, textMatchTransformers)
return
}
let currentNode, remainderNode, leadingNode
// If matching full content there's no need to run splitText and can reuse existing textNode
// to update its content and apply format. E.g. for **_Hello_** string after applying bold
// format (**) it will reuse the same text node to apply italic (_)
if (match[0] === textContent) {
currentNode = textNode
} else {
const startIndex = match.index || 0
const endIndex = startIndex + match[0].length
if (startIndex === 0) {
;[currentNode, remainderNode] = textNode.splitText(endIndex)
} else {
;[leadingNode, currentNode, remainderNode] = textNode.splitText(startIndex, endIndex)
}
}
currentNode.setTextContent(match[2])
const transformer = textFormatTransformersIndex.transformersByTag[match[1]]
if (transformer) {
for (const format of transformer.format) {
if (!currentNode.hasFormat(format)) {
currentNode.toggleFormat(format)
}
}
}
// Recursively run over inner text if it's not inline code
if (!currentNode.hasFormat('code')) {
importTextFormatTransformers(currentNode, textFormatTransformersIndex, textMatchTransformers)
}
// Run over leading/remaining text if any
if (leadingNode) {
importTextFormatTransformers(leadingNode, textFormatTransformersIndex, textMatchTransformers)
}
if (remainderNode) {
importTextFormatTransformers(remainderNode, textFormatTransformersIndex, textMatchTransformers)
}
}
function importTextMatchTransformers(textNode_: TextNode, textMatchTransformers: Array<TextMatchTransformer>) {
let textNode = textNode_
mainLoop: while (textNode) {
for (const transformer of textMatchTransformers) {
const match = textNode.getTextContent().match(transformer.importRegExp)
if (!match) {
continue
}
const startIndex = match.index || 0
const endIndex = startIndex + match[0].length
let replaceNode, newTextNode
if (startIndex === 0) {
;[replaceNode, textNode] = textNode.splitText(endIndex)
} else {
;[, replaceNode, newTextNode] = textNode.splitText(startIndex, endIndex)
}
if (newTextNode) {
importTextMatchTransformers(newTextNode, textMatchTransformers)
}
transformer.replace(replaceNode, match)
continue mainLoop
}
break
}
}
// Finds first "<tag>content<tag>" match that is not nested into another tag
function findOutermostMatch(
textContent: string,
textTransformersIndex: TextFormatTransformersIndex,
): RegExpMatchArray | null {
const openTagsMatch = textContent.match(textTransformersIndex.openTagsRegExp)
if (openTagsMatch == null) {
return null
}
for (const match of openTagsMatch) {
// Open tags reg exp might capture leading space so removing it
// before using match to find transformer
const tag = match.replace(/^\s/, '')
const fullMatchRegExp = textTransformersIndex.fullMatchRegExpByTag[tag]
if (fullMatchRegExp == null) {
continue
}
const fullMatch = textContent.match(fullMatchRegExp)
const transformer = textTransformersIndex.transformersByTag[tag]
if (fullMatch != null && transformer != null) {
if (transformer.intraword !== false) {
return fullMatch
}
// For non-intraword transformers checking if it's within a word
// or surrounded with space/punctuation/newline
const { index = 0 } = fullMatch
const beforeChar = textContent[index - 1]
const afterChar = textContent[index + fullMatch[0].length]
if (
(!beforeChar || PUNCTUATION_OR_SPACE.test(beforeChar)) &&
(!afterChar || PUNCTUATION_OR_SPACE.test(afterChar))
) {
return fullMatch
}
}
}
return null
}
function createTextFormatTransformersIndex(
textTransformers: Array<TextFormatTransformer>,
): TextFormatTransformersIndex {
const transformersByTag: Record<string, TextFormatTransformer> = {}
const fullMatchRegExpByTag: Record<string, RegExp> = {}
const openTagsRegExp = []
const escapeRegExp = '(?<![\\\\])'
for (const transformer of textTransformers) {
const { tag } = transformer
transformersByTag[tag] = transformer
const tagRegExp = tag.replace(/(\*|\^|\+)/g, '\\$1')
openTagsRegExp.push(tagRegExp)
if (IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT) {
fullMatchRegExpByTag[tag] = new RegExp(
`(${tagRegExp})(?![${tagRegExp}\\s])(.*?[^${tagRegExp}\\s])${tagRegExp}(?!${tagRegExp})`,
)
} else {
fullMatchRegExpByTag[tag] = new RegExp(
`(?<![\\\\${tagRegExp}])(${tagRegExp})((\\\\${tagRegExp})?.*?[^${tagRegExp}\\s](\\\\${tagRegExp})?)((?<!\\\\)|(?<=\\\\\\\\))(${tagRegExp})(?![\\\\${tagRegExp}])`,
)
}
}
return {
// Reg exp to find open tag + content + close tag
fullMatchRegExpByTag,
// Reg exp to find opening tags
openTagsRegExp: new RegExp(
(IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT ? '' : `${escapeRegExp}`) + '(' + openTagsRegExp.join('|') + ')',
'g',
),
transformersByTag,
}
}
export function $convertFromMarkdownString(
markdown: string,
transformers: Array<Transformer> = TRANSFORMERS,
node?: ElementNode,
keepNewLines = false,
): void {
const importMarkdown = createMarkdownImport(transformers)
return importMarkdown(markdown, node, keepNewLines)
}

View file

@ -6,7 +6,10 @@ import {
ELEMENT_TRANSFORMERS,
TEXT_FORMAT_TRANSFORMERS,
TEXT_MATCH_TRANSFORMERS,
MultilineElementTransformer,
MULTILINE_ELEMENT_TRANSFORMERS,
} from '@lexical/markdown'
import { LexicalNode, $isParagraphNode, $isTextNode } from 'lexical'
function indexBy<T>(list: Array<T>, callback: (arg0: T) => string): Readonly<Record<string, Array<T>>> {
const index: Record<string, Array<T>> = {}
@ -26,6 +29,7 @@ function indexBy<T>(list: Array<T>, callback: (arg0: T) => string): Readonly<Rec
export function transformersByType(transformers: Array<Transformer>): Readonly<{
element: Array<ElementTransformer>
multilineElement: Array<MultilineElementTransformer>
textFormat: Array<TextFormatTransformer>
textMatch: Array<TextMatchTransformer>
}> {
@ -33,13 +37,31 @@ export function transformersByType(transformers: Array<Transformer>): Readonly<{
return {
element: (byType.element || []) as Array<ElementTransformer>,
multilineElement: (byType['multiline-element'] || []) as Array<MultilineElementTransformer>,
textFormat: (byType['text-format'] || []) as Array<TextFormatTransformer>,
textMatch: (byType['text-match'] || []) as Array<TextMatchTransformer>,
}
}
const MARKDOWN_EMPTY_LINE_REG_EXP = /^\s{0,3}$/
export function isEmptyParagraph(node: LexicalNode): boolean {
if (!$isParagraphNode(node)) {
return false
}
const firstChild = node.getFirstChild()
return (
firstChild == null ||
(node.getChildrenSize() === 1 &&
$isTextNode(firstChild) &&
MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent()))
)
}
export const TRANSFORMERS: Array<Transformer> = [
...ELEMENT_TRANSFORMERS,
...MULTILINE_ELEMENT_TRANSFORMERS,
...TEXT_FORMAT_TRANSFORMERS,
...TEXT_MATCH_TRANSFORMERS,
]

View file

@ -7,6 +7,7 @@ import {
TextMatchTransformer,
$convertToMarkdownString,
$convertFromMarkdownString,
MULTILINE_ELEMENT_TRANSFORMERS,
} from '@lexical/markdown'
import {
$createTableCellNode,
@ -247,6 +248,7 @@ export const MarkdownTransformers = [
IMAGE,
INLINE_FILE,
...ELEMENT_TRANSFORMERS,
...MULTILINE_ELEMENT_TRANSFORMERS,
...TEXT_FORMAT_TRANSFORMERS,
...TEXT_MATCH_TRANSFORMERS,
HorizontalRule,

View file

@ -44,14 +44,14 @@ export class CollapsibleContainerNode extends ElementNode {
this.__open = open ?? false
}
static override getType(): string {
return 'collapsible-container'
}
static override clone(node: CollapsibleContainerNode): CollapsibleContainerNode {
return new CollapsibleContainerNode(node.__open, node.__key)
}
static override getType(): string {
return 'collapsible-container'
}
override createDOM(_: EditorConfig, editor: LexicalEditor): HTMLElement {
const dom = document.createElement('details')
dom.classList.add('Collapsible__container')

View file

@ -13,6 +13,12 @@ export class FileNode extends DecoratorBlockNode implements ItemNodeInterface {
return 'snfile'
}
constructor(id: string, format?: ElementFormatType, key?: NodeKey, zoomLevel?: number) {
super(format, key)
this.__id = id
this.__zoomLevel = zoomLevel || 100
}
static clone(node: FileNode): FileNode {
return new FileNode(node.__id, node.__format, node.__key, node.__zoomLevel)
}
@ -56,12 +62,6 @@ export class FileNode extends DecoratorBlockNode implements ItemNodeInterface {
return { element }
}
constructor(id: string, format?: ElementFormatType, key?: NodeKey, zoomLevel?: number) {
super(format, key)
this.__id = id
this.__zoomLevel = zoomLevel || 100
}
getId(): string {
return this.__id
}

View file

@ -5,7 +5,7 @@ import { handleEditorChange } from '../../Utils'
import { SuperNotePreviewCharLimit } from '../../SuperEditor'
import { $generateNodesFromDOM } from '@lexical/html'
import { MarkdownTransformers } from '../../MarkdownTransformers'
import { $convertFromMarkdownString } from '../../Lexical/Utils/MarkdownImport'
import { $convertFromMarkdownString } from '@lexical/markdown'
/** Note that markdown conversion does not insert new lines. See: https://github.com/facebook/lexical/issues/2815 */
export default function ImportPlugin({

View file

@ -1,5 +1,14 @@
import { DecoratorBlockNode, SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode'
import { DOMConversionMap, DOMExportOutput, EditorConfig, LexicalEditor, LexicalNode, Spread } from 'lexical'
import {
DOMConversionMap,
DOMExportOutput,
EditorConfig,
ElementFormatType,
LexicalEditor,
LexicalNode,
NodeKey,
Spread,
} from 'lexical'
import InlineFileComponent from './InlineFileComponent'
type SerializedInlineFileNode = Spread<
@ -22,15 +31,15 @@ export class InlineFileNode extends DecoratorBlockNode {
return 'inline-file'
}
constructor(src: string, mimeType: string, fileName: string | undefined) {
super()
constructor(src: string, mimeType: string, fileName: string | undefined, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__src = src
this.__mimeType = mimeType
this.__fileName = fileName
}
static clone(node: InlineFileNode): InlineFileNode {
return new InlineFileNode(node.__src, node.__mimeType, node.__fileName)
return new InlineFileNode(node.__src, node.__mimeType, node.__fileName, node.__format, node.__key)
}
static importJSON(serializedNode: SerializedInlineFileNode): InlineFileNode {

View file

@ -1,9 +1,10 @@
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { useEffect } from 'react'
import { $createCodeNode } from '@lexical/code'
import { $createTextNode, $getRoot, $nodesOfType, ParagraphNode } from 'lexical'
import { $convertToMarkdownString } from '@lexical/markdown'
import { $createTextNode, $getRoot, $isParagraphNode } from 'lexical'
import { MarkdownTransformers } from '../../MarkdownTransformers'
import { $dfs } from '@lexical/utils'
import { $convertToMarkdownString } from '../../Lexical/Utils/MarkdownExport'
type Props = {
onMarkdown: (markdown: string) => void
@ -15,10 +16,12 @@ export default function MarkdownPreviewPlugin({ onMarkdown }: Props): JSX.Elemen
useEffect(() => {
editor.update(() => {
const root = $getRoot()
const paragraphs = $nodesOfType(ParagraphNode)
for (const paragraph of paragraphs) {
if (paragraph.isEmpty()) {
paragraph.remove()
for (const { node } of $dfs()) {
if (!$isParagraphNode(node)) {
continue
}
if (node.isEmpty()) {
node.remove()
}
}
const markdown = $convertToMarkdownString(MarkdownTransformers)

View file

@ -1,5 +1,14 @@
import { DecoratorBlockNode, SerializedDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode'
import { DOMConversionMap, DOMExportOutput, EditorConfig, LexicalEditor, LexicalNode, Spread } from 'lexical'
import {
DOMConversionMap,
DOMExportOutput,
EditorConfig,
ElementFormatType,
LexicalEditor,
LexicalNode,
NodeKey,
Spread,
} from 'lexical'
import RemoteImageComponent from './RemoteImageComponent'
type SerializedRemoteImageNode = Spread<
@ -20,14 +29,14 @@ export class RemoteImageNode extends DecoratorBlockNode {
return 'unencrypted-image'
}
constructor(src: string, alt?: string) {
super()
constructor(src: string, alt?: string, format?: ElementFormatType, key?: NodeKey) {
super(format, key)
this.__src = src
this.__alt = alt
}
static clone(node: RemoteImageNode): RemoteImageNode {
return new RemoteImageNode(node.__src, node.__alt)
return new RemoteImageNode(node.__src, node.__alt, node.__format, node.__key)
}
static importJSON(serializedNode: SerializedRemoteImageNode): RemoteImageNode {

View file

@ -89,9 +89,10 @@ export const SearchPlugin = () => {
const handleSearch = useCallback(
(query: string, isCaseSensitive: boolean) => {
document.querySelectorAll('.search-highlight').forEach((element) => {
const currentHighlights = document.querySelectorAll('.search-highlight')
for (const element of currentHighlights) {
element.remove()
})
}
if (!query) {
dispatch({ type: 'clear-results' })
@ -109,7 +110,7 @@ export const SearchPlugin = () => {
const results: SuperSearchResult[] = []
textNodes.forEach((node) => {
for (const node of textNodes) {
const text = node.textContent || ''
const indices: number[] = []
@ -122,7 +123,7 @@ export const SearchPlugin = () => {
indices.push(index)
}
indices.forEach((index) => {
for (const index of indices) {
const startIndex = index
const endIndex = startIndex + query.length
@ -131,8 +132,8 @@ export const SearchPlugin = () => {
startIndex,
endIndex,
})
})
})
}
}
dispatch({
type: 'set-results',
@ -205,7 +206,10 @@ export const SearchPlugin = () => {
}
replaceResult(result, true)
} else if (type === 'all') {
resultsRef.current.forEach((result) => replaceResult(result))
const results = resultsRef.current
for (const result of results) {
replaceResult(result)
}
}
void handleSearch(queryRef.current, isCaseSensitiveRef.current)
@ -214,9 +218,10 @@ export const SearchPlugin = () => {
}, [addReplaceEventListener, currentResultIndexRef, editor, handleSearch, isCaseSensitiveRef, queryRef, resultsRef])
useEffect(() => {
document.querySelectorAll('.search-highlight').forEach((element) => {
const currentHighlights = document.querySelectorAll('.search-highlight')
for (const element of currentHighlights) {
element.remove()
})
}
if (currentResultIndex === -1) {
return
}

View file

@ -190,7 +190,7 @@ function TableActionMenu({ onClose, tableCellNode: _tableCellNode, cellMerge }:
const tableSelection = getTableObserverFromTableElement(tableElement)
if (tableSelection !== null) {
tableSelection.clearHighlight()
tableSelection.$clearHighlight()
}
tableNode.markDirty()

View file

@ -1,24 +1,17 @@
import { createHeadlessEditor } from '@lexical/headless'
import { FileItem, PrefKey, PrefValue, SuperConverterServiceInterface } from '@standardnotes/snjs'
import {
$createParagraphNode,
$getRoot,
$insertNodes,
$nodesOfType,
LexicalEditor,
LexicalNode,
ParagraphNode,
} from 'lexical'
import { $createParagraphNode, $getRoot, $insertNodes, $isParagraphNode, LexicalEditor, LexicalNode } from 'lexical'
import BlocksEditorTheme from '../Lexical/Theme/Theme'
import { BlockEditorNodes, SuperExportNodes } from '../Lexical/Nodes/AllNodes'
import { MarkdownTransformers } from '../MarkdownTransformers'
import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html'
import { FileNode } from '../Plugins/EncryptedFilePlugin/Nodes/FileNode'
import { $createFileExportNode } from '../Lexical/Nodes/FileExportNode'
import { $createInlineFileNode } from '../Plugins/InlineFilePlugin/InlineFileNode'
import { $convertFromMarkdownString } from '../Lexical/Utils/MarkdownImport'
import { $convertFromMarkdownString } from '@lexical/markdown'
import { $convertToMarkdownString } from '../Lexical/Utils/MarkdownExport'
import { parseFileName } from '@standardnotes/utils'
import { $dfs } from '@lexical/utils'
import { $isFileNode } from '../Plugins/EncryptedFilePlugin/Nodes/FileUtils'
export class HeadlessSuperConverter implements SuperConverterServiceInterface {
private importEditor: LexicalEditor
@ -80,103 +73,103 @@ export class HeadlessSuperConverter implements SuperConverterServiceInterface {
let content: string | undefined
await new Promise<void>((resolve) => {
this.exportEditor.update(
() => {
if (embedBehavior === 'reference') {
resolve()
return
}
if (!getFileItem) {
resolve()
return
}
const fileNodes = $nodesOfType(FileNode)
const filenameCounts: Record<string, number> = {}
Promise.all(
fileNodes.map(async (fileNode) => {
const fileItem = getFileItem(fileNode.getId())
if (!fileItem) {
const handleFileNodes = () => {
if (embedBehavior === 'reference') {
resolve()
return
}
if (!getFileItem) {
resolve()
return
}
const filenameCounts: Record<string, number> = {}
Promise.all(
$dfs().map(async ({ node: fileNode }) => {
if (!$isFileNode(fileNode)) {
return
}
const fileItem = getFileItem(fileNode.getId())
if (!fileItem) {
return
}
const canInlineFileType = toFormat === 'pdf' ? fileItem.mimeType.startsWith('image/') : true
if (embedBehavior === 'inline' && getFileBase64 && canInlineFileType) {
const fileBase64 = await getFileBase64(fileNode.getId())
if (!fileBase64) {
return
}
const canInlineFileType = toFormat === 'pdf' ? fileItem.mimeType.startsWith('image/') : true
if (embedBehavior === 'inline' && getFileBase64 && canInlineFileType) {
const fileBase64 = await getFileBase64(fileNode.getId())
if (!fileBase64) {
return
}
this.exportEditor.update(
() => {
const inlineFileNode = $createInlineFileNode(fileBase64, fileItem.mimeType, fileItem.name)
fileNode.replace(inlineFileNode)
},
{ discrete: true },
)
} else {
this.exportEditor.update(
() => {
filenameCounts[fileItem.name] =
filenameCounts[fileItem.name] == undefined ? 0 : filenameCounts[fileItem.name] + 1
this.exportEditor.update(
() => {
const inlineFileNode = $createInlineFileNode(fileBase64, fileItem.mimeType, fileItem.name)
fileNode.replace(inlineFileNode)
},
{ discrete: true },
)
} else {
this.exportEditor.update(
() => {
filenameCounts[fileItem.name] =
filenameCounts[fileItem.name] == undefined ? 0 : filenameCounts[fileItem.name] + 1
let name = fileItem.name
let name = fileItem.name
if (filenameCounts[name] > 0) {
const { name: _name, ext } = parseFileName(name)
name = `${_name}-${fileItem.uuid}.${ext}`
}
if (filenameCounts[name] > 0) {
const { name: _name, ext } = parseFileName(name)
name = `${_name}-${fileItem.uuid}.${ext}`
}
const fileExportNode = $createFileExportNode(name, fileItem.mimeType)
fileNode.replace(fileExportNode)
},
{ discrete: true },
)
}
}),
)
.then(() => resolve())
.catch(console.error)
},
{ discrete: true },
)
const fileExportNode = $createFileExportNode(name, fileItem.mimeType)
fileNode.replace(fileExportNode)
},
{ discrete: true },
)
}
}),
)
.then(() => resolve())
.catch(console.error)
}
this.exportEditor.update(handleFileNodes, { discrete: true })
})
await new Promise<void>((resolve) => {
this.exportEditor.update(
() => {
switch (toFormat) {
case 'txt':
case 'md': {
const paragraphs = $nodesOfType(ParagraphNode)
for (const paragraph of paragraphs) {
if (paragraph.isEmpty()) {
paragraph.remove()
}
const convertToFormat = () => {
switch (toFormat) {
case 'txt':
case 'md': {
for (const { node: paragraph } of $dfs()) {
if (!$isParagraphNode(paragraph)) {
continue
}
if (paragraph.isEmpty()) {
paragraph.remove()
}
content = $convertToMarkdownString(MarkdownTransformers)
resolve()
break
}
case 'html':
content = $generateHtmlFromNodes(this.exportEditor)
resolve()
break
case 'pdf': {
void import('../Lexical/Utils/PDFExport/PDFExport').then(({ $generatePDFFromNodes }): void => {
void $generatePDFFromNodes(this.exportEditor, config?.pdf?.pageSize || 'A4').then((pdf) => {
content = pdf
resolve()
})
})
break
}
case 'json':
default:
content = superString
resolve()
break
content = $convertToMarkdownString(MarkdownTransformers)
resolve()
break
}
},
{ discrete: true },
)
case 'html':
content = $generateHtmlFromNodes(this.exportEditor)
resolve()
break
case 'pdf': {
void import('../Lexical/Utils/PDFExport/PDFExport').then(({ $generatePDFFromNodes }): void => {
void $generatePDFFromNodes(this.exportEditor, config?.pdf?.pageSize || 'A4').then((pdf) => {
content = pdf
resolve()
})
})
break
}
case 'json':
default:
content = superString
resolve()
break
}
}
this.exportEditor.update(convertToFormat, { discrete: true })
})
if (typeof content !== 'string') {
@ -288,14 +281,16 @@ export class HeadlessSuperConverter implements SuperConverterServiceInterface {
const ids: string[] = []
this.exportEditor.getEditorState().read(() => {
const fileNodes = $nodesOfType(FileNode)
fileNodes.forEach((fileNode) => {
for (const { node: fileNode } of $dfs()) {
if (!$isFileNode(fileNode)) {
continue
}
const nodeId = fileNode.getId()
if (ids.includes(nodeId)) {
return
continue
}
ids.push(nodeId)
})
}
})
return ids

394
yarn.lock
View file

@ -4278,298 +4278,290 @@ __metadata:
languageName: node
linkType: hard
"@lexical/clipboard@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/clipboard@npm:0.16.0"
"@lexical/clipboard@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/clipboard@npm:0.22.0"
dependencies:
"@lexical/html": 0.16.0
"@lexical/list": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 8fe5cf11a1ad84d4da39205610cb2969046455a0dc0b33d4de748abc9fe9904c2381ce85c495f2b9c85233548d7223270eec030619f3455bb911d6767a3516f2
"@lexical/html": 0.22.0
"@lexical/list": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: c6869ec54c6972185806ab40b35a089cbb54585ccd13f38e0e56cdac1783b0615f2482adf15505279b0b0f2276a2a1fa432673983c7f9a5ed3274d4e8588939c
languageName: node
linkType: hard
"@lexical/clipboard@patch:@lexical/clipboard@npm:0.16.0#.yarn/patches/@lexical-clipboard-npm-0.16.0-3053c4af9c.patch::locator=%40standardnotes%2Fapp-monorepo%40workspace%3A.":
version: 0.16.0
resolution: "@lexical/clipboard@patch:@lexical/clipboard@npm%3A0.16.0#.yarn/patches/@lexical-clipboard-npm-0.16.0-3053c4af9c.patch::version=0.16.0&hash=ef7a9a&locator=%40standardnotes%2Fapp-monorepo%40workspace%3A."
"@lexical/clipboard@patch:@lexical/clipboard@npm:0.22.0#.yarn/patches/@lexical-clipboard-npm-0.22.0-e950aa6a7f.patch::locator=%40standardnotes%2Fapp-monorepo%40workspace%3A.":
version: 0.22.0
resolution: "@lexical/clipboard@patch:@lexical/clipboard@npm%3A0.22.0#.yarn/patches/@lexical-clipboard-npm-0.22.0-e950aa6a7f.patch::version=0.22.0&hash=30572a&locator=%40standardnotes%2Fapp-monorepo%40workspace%3A."
dependencies:
"@lexical/html": 0.16.0
"@lexical/list": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 4bfeeaef9a31d15bfa35bc58d4508ec19eeb3a8c68f88a5d1eb69bcba007fca934c0cd278d3b10adf754b0b9370a0aa16e48d31f26fa3a7d7a95bfa736f0417c
"@lexical/html": 0.22.0
"@lexical/list": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 8972b49800b7491072680ed597a81b934b388f97570b8239f14dabfbafd6f4e46feeb68e279a9e8c5075e955310b6dac480bb1c8f2f2e1d98f900705cd8b1168
languageName: node
linkType: hard
"@lexical/code@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/code@npm:0.16.0"
"@lexical/code@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/code@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
prismjs: ^1.27.0
checksum: 4f6283beca15df5b9520f2245803f7e34fc4297fbaafd790371d44a590a8ba33107515f63a8db281191280d85b170c7eca3fc151eec5929b3b5a212cc5255ecf
checksum: 6e7ff958d5dbbe02e8ca998d5601aea545fe18a509368170002fb0906a020d2d1d93fffaa6442ee742c78350eb74419a09521084e10859e801de95bb2cd8cada
languageName: node
linkType: hard
"@lexical/devtools-core@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/devtools-core@npm:0.16.0"
"@lexical/devtools-core@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/devtools-core@npm:0.22.0"
dependencies:
"@lexical/html": 0.16.0
"@lexical/link": 0.16.0
"@lexical/mark": 0.16.0
"@lexical/table": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
"@lexical/html": 0.22.0
"@lexical/link": 0.22.0
"@lexical/mark": 0.22.0
"@lexical/table": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
peerDependencies:
react: ">=17.x"
react-dom: ">=17.x"
checksum: c6ba99da01c2bef29537e0c3f39f0e6c91a6c091239b96048ae9cba5d9911edac9906f053430e17599608d9d01721efbeca00471dfb8ce7878492f767105e056
checksum: e8c75cd1fb5854e51d6565ff46cd4c1118991d0b069e7d3f3a9cc59a997a9495947bef2b77752ff0a63799fdc5bc28a02d168ff4cef92ac697089746859bb2af
languageName: node
linkType: hard
"@lexical/dragon@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/dragon@npm:0.16.0"
"@lexical/dragon@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/dragon@npm:0.22.0"
dependencies:
lexical: 0.16.0
checksum: 8f6fa617559bdf204da8509d545e34f78d19c8268a8335bf7e62621f053f88e328521879cf60e8e6eab85d7580681b09ed90dc77a6088aaac32d0f62f860f1dd
lexical: 0.22.0
checksum: ba9b4143b7b01a3cc938c673c32ec2dfc944dc529fd204cbf63f4376b2b6d8481270ae72a7c241cbe3b9488e0af67f8c7017873723f903a0ddd5e14967cbe12b
languageName: node
linkType: hard
"@lexical/hashtag@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/hashtag@npm:0.16.0"
"@lexical/hashtag@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/hashtag@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: a569b35a89708d6291c072ac91dbf69b759383862633fc1d8f2322ebdec9b4200f8f5a3c30f46f58963c80290ba3182da8d44d468f352760b85e00e760db2753
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 368cf96b0851ed47359228ab5b363d62d705c226e3ce67e65cc94e446d6ddd50d4a27634f164fb171f09fb30461c5b015d5f602894ebe712bed0802ea6bd8473
languageName: node
linkType: hard
"@lexical/headless@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/headless@npm:0.16.0"
"@lexical/headless@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/headless@npm:0.22.0"
dependencies:
lexical: 0.16.0
checksum: 6a03375495e839965b52d2d5980ffd821dd9f72acfb8793df74db2fed424cb9e9cd787d76684112651efdaa9c1af6feae4674dbb79b67edcd7b37331f67880b1
lexical: 0.22.0
checksum: dedc45cec5e1bd6249c3debded120d0c9b09c924dc0e6625d2d6d9e1ce08625722510f0beb8380ce8bb96f3006510375450e88a80fbc366c45ad6df6e660f4ff
languageName: node
linkType: hard
"@lexical/history@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/history@npm:0.16.0"
"@lexical/history@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/history@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: a26311ddcc2a283eb069abd4fc6963d3401b57e618bfdb061a7f36b376a04af32223b3d63575185cf7e38de34416efe4e184979f42a4a71395ffad54e5337cf0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 8eb683a5bbe6ab1c5936be81d480a1519c7c2b0931b1957e71a1b873655155967635b18fc26f8a6228b0c8e0dc7c0c4b7e3e91bce064d003d9609350916bfed8
languageName: node
linkType: hard
"@lexical/html@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/html@npm:0.16.0"
"@lexical/html@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/html@npm:0.22.0"
dependencies:
"@lexical/selection": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 3b3ffa982318a46bfa189805352dda6e3139b10c2b9e4242efce98037bbb26eeb7656bd169b5e2666503cd91cdf93ac7e154f10905eb9cffa4a092b11e0811d9
"@lexical/selection": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 14e32af4fbe3ee06cb48587ba6302e451360f6d3dbacef191032d80464727593d7fe98a44875809666ba8cd169c73241cd841326cf54edef235ddb24515d7ef0
languageName: node
linkType: hard
"@lexical/link@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/link@npm:0.16.0"
"@lexical/link@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/link@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 2b2900001a97bf22550f0141dea358bbb7fe1b59bffe7506afd5e834ec722371de4d62b9e9899a4a960d3d85369bfe3faf5ba79367640b9e45b7bcff46bf1409
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: f36c3d3a7e05308f02b402a4645bf00ffe8f61223c7a8f8e59c61ee8fabdbf77aac95d7a6e04c68490aa5b701a620fa89cd323a135963f85f5d82a5e6417efae
languageName: node
linkType: hard
"@lexical/list@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/list@npm:0.16.0"
"@lexical/list@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/list@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: f60fd40d03b276624b67371498f42cd70fb8ad6971d0c3e396681e8f3c2fc2d9678472912363388c4b7913c93bc526f2400b925dbc3cfcdb61aea06a0af53a0b
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 7ee86ccc5686a23c365b38c3df3e6c1da560dfc6d7e4ad66e06d9e1b759b68276e1b24bb0f94906462e20d7778a55897909030ff35f03836e178b8ce68d70c1e
languageName: node
linkType: hard
"@lexical/list@patch:@lexical/list@npm:0.16.0#.yarn/patches/@lexical-list-npm-0.16.0-8f91da4ad5.patch::locator=%40standardnotes%2Fapp-monorepo%40workspace%3A.":
version: 0.16.0
resolution: "@lexical/list@patch:@lexical/list@npm%3A0.16.0#.yarn/patches/@lexical-list-npm-0.16.0-8f91da4ad5.patch::version=0.16.0&hash=6af727&locator=%40standardnotes%2Fapp-monorepo%40workspace%3A."
"@lexical/mark@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/mark@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: bb546181595b39180ce4b733f36ea34adf1b6f89cdee1ffd74b4ece4b299e9ef51a0b269e8eb90dcbff10b78f2f3ddd333d611a7c91defe218f2b717cf9ca93b
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: c3cf36c47b03944d90f67d4ced88f4e6702c629647e4e0ba70ee5fbcbd3fab424b7602f55b63c37bafdcc146fcaf2186348ed6fa08ef586ad6ce5d6320ba66a9
languageName: node
linkType: hard
"@lexical/mark@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/mark@npm:0.16.0"
"@lexical/markdown@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/markdown@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 08067e266d0518bce4aa402e73dc066a6be3af138a4cee76f2255725b2032248bdc4ebd98a85b19923c441853cfde154f12e3b87eae8ae203bca30f0e4d49700
"@lexical/code": 0.22.0
"@lexical/link": 0.22.0
"@lexical/list": 0.22.0
"@lexical/rich-text": 0.22.0
"@lexical/text": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 0e2c371ead6434be1bc62eda95fe19a15a638382c659921f83bc41f5f2229de3f74982cc9ab1a9e7bcd5831fcd273d262f9d94d094300a4901ed48205f4dfafe
languageName: node
linkType: hard
"@lexical/markdown@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/markdown@npm:0.16.0"
"@lexical/offset@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/offset@npm:0.22.0"
dependencies:
"@lexical/code": 0.16.0
"@lexical/link": 0.16.0
"@lexical/list": 0.16.0
"@lexical/rich-text": 0.16.0
"@lexical/text": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 2d061e4a3b0f8eee0c7975cfff8043601a435aece33c06c0e717a639cf680fa68e3727b95247468cb55d81e1d8970ee8ea8b9348d8bef755b968dc306be19792
lexical: 0.22.0
checksum: 9172370f74f8c9f444a3bba778975de340b61d232d2736a392e2fa4506953819e9131f6369c4a03afe2f913a288fffca8267e09a0943521b57e7e6ddeefe4d63
languageName: node
linkType: hard
"@lexical/offset@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/offset@npm:0.16.0"
"@lexical/overflow@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/overflow@npm:0.22.0"
dependencies:
lexical: 0.16.0
checksum: c6c581be2f084d20aa2b1ef7b0d3deaac9b4550792f9278a35427d493d35d68aaf7ec2eb4357b5defa61c50001928c74199d7867a94670cda648944451bfbfbf
lexical: 0.22.0
checksum: 9b486682927089e61de4243f7097da8f6c7f7cbf57e1c1da666b10e417c54a444459bc8daaca5b885c24d4cb427eb9ff1554606b01299c2bf645bf5a560b32f1
languageName: node
linkType: hard
"@lexical/overflow@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/overflow@npm:0.16.0"
"@lexical/plain-text@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/plain-text@npm:0.22.0"
dependencies:
lexical: 0.16.0
checksum: 9b659e40537ffd09ab3f8a6ba7e61eb7adddaefb0dd4922d7cb912e2d94c606960a5d8e7737267fc36e95792526cb9b158f3605bedcdade0ce1594895ee0304b
"@lexical/clipboard": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 1093ebfc11f13b0767dab3c1e29c55fbaae6b1ff1979d5c66b0e07f8589a2ba602b5c40633575d90152031623dc3cf66a12c5915e6606974b925389e9cedc02b
languageName: node
linkType: hard
"@lexical/plain-text@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/plain-text@npm:0.16.0"
"@lexical/react@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/react@npm:0.22.0"
dependencies:
"@lexical/clipboard": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 026a745849ed6cc6fe7b68cc1982f1be32fbe56c63a5afd27383f786482438cb38ab7b06d3e2cb8dfd0c689ea92d12ba6be62a453ea52c068e5df57c7489d453
languageName: node
linkType: hard
"@lexical/react@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/react@npm:0.16.0"
dependencies:
"@lexical/clipboard": 0.16.0
"@lexical/code": 0.16.0
"@lexical/devtools-core": 0.16.0
"@lexical/dragon": 0.16.0
"@lexical/hashtag": 0.16.0
"@lexical/history": 0.16.0
"@lexical/link": 0.16.0
"@lexical/list": 0.16.0
"@lexical/mark": 0.16.0
"@lexical/markdown": 0.16.0
"@lexical/overflow": 0.16.0
"@lexical/plain-text": 0.16.0
"@lexical/rich-text": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/table": 0.16.0
"@lexical/text": 0.16.0
"@lexical/utils": 0.16.0
"@lexical/yjs": 0.16.0
lexical: 0.16.0
"@lexical/clipboard": 0.22.0
"@lexical/code": 0.22.0
"@lexical/devtools-core": 0.22.0
"@lexical/dragon": 0.22.0
"@lexical/hashtag": 0.22.0
"@lexical/history": 0.22.0
"@lexical/link": 0.22.0
"@lexical/list": 0.22.0
"@lexical/mark": 0.22.0
"@lexical/markdown": 0.22.0
"@lexical/overflow": 0.22.0
"@lexical/plain-text": 0.22.0
"@lexical/rich-text": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/table": 0.22.0
"@lexical/text": 0.22.0
"@lexical/utils": 0.22.0
"@lexical/yjs": 0.22.0
lexical: 0.22.0
react-error-boundary: ^3.1.4
peerDependencies:
react: ">=17.x"
react-dom: ">=17.x"
checksum: a58988010f1ae2182b0779280e92086bfe9c36f15baf96d069b1c81da48595579afaf01bbf69ecb3a10fdad01a32eda134bfe5efde31e545711c68516a088018
checksum: 6d4f56be0bac9f7dd31b9855cab97b4b24bb93a5d998e6065ab6d0bc987fde42d674fc608547e47c108ef31250c7c77a703943560dd5d980629604a582d019b1
languageName: node
linkType: hard
"@lexical/rich-text@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/rich-text@npm:0.16.0"
"@lexical/rich-text@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/rich-text@npm:0.22.0"
dependencies:
"@lexical/clipboard": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 00318a6a7813406e7f1c3fe7509c622ecaeb336c4b3c8bfef428cc7aa4dd5a8af4d2110e4884b6880ea28663b97ab0e8a9b3e9282de3fc7aa4aba910d215431e
"@lexical/clipboard": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: f7c7153b16406c41a4b770a11c6abb48eb919edb2e7cec36ffcebee4889e70110a0a03ee545572c96bf5f4dc1be233572fb4c2e0336016031460d203b486fa27
languageName: node
linkType: hard
"@lexical/rich-text@patch:@lexical/rich-text@npm:0.16.0#.yarn/patches/@lexical-rich-text-npm-0.16.0-f484a17832.patch::locator=%40standardnotes%2Fapp-monorepo%40workspace%3A.":
version: 0.16.0
resolution: "@lexical/rich-text@patch:@lexical/rich-text@npm%3A0.16.0#.yarn/patches/@lexical-rich-text-npm-0.16.0-f484a17832.patch::version=0.16.0&hash=24f58c&locator=%40standardnotes%2Fapp-monorepo%40workspace%3A."
"@lexical/rich-text@patch:@lexical/rich-text@npm:0.22.0#.yarn/patches/@lexical-rich-text-npm-0.22.0-1c32cc4b16.patch::locator=%40standardnotes%2Fapp-monorepo%40workspace%3A.":
version: 0.22.0
resolution: "@lexical/rich-text@patch:@lexical/rich-text@npm%3A0.22.0#.yarn/patches/@lexical-rich-text-npm-0.22.0-1c32cc4b16.patch::version=0.22.0&hash=d9e598&locator=%40standardnotes%2Fapp-monorepo%40workspace%3A."
dependencies:
"@lexical/clipboard": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: fb69c079641d385e4aa5f6568769051837fbd7dac9db264d10dcb95326bd79f94379cda43e157d53d7a01849722bd3ad82f15c7cff5f2fa365d203f41f5ad159
"@lexical/clipboard": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: c6523beac513a4a654329813056e5e45a4ec089dcd7ba3767fcf7a8b6dab778725fdd1da1dc171929d15ca5afd7e57e4c36667df7b28e9cd1836c973dee5bb08
languageName: node
linkType: hard
"@lexical/selection@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/selection@npm:0.16.0"
"@lexical/selection@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/selection@npm:0.22.0"
dependencies:
lexical: 0.16.0
checksum: fd4832f3b01018b4025706ea86ada3e3dd5a70e2b73722d993fb7e272c3fa2a339e22c914f5fb1836ae077a56daefc6b16dfa77477c56648135ef6ea5ba53f05
lexical: 0.22.0
checksum: 5c3f80944e8b55b911ddb08af3ff3529b0ce1708f9b86ba8a276ad248c61eea5df767e66c624efbab696941622e1114016fab06931f5f9340d2818fb93ed2d6f
languageName: node
linkType: hard
"@lexical/table@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/table@npm:0.16.0"
"@lexical/table@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/table@npm:0.22.0"
dependencies:
"@lexical/utils": 0.16.0
lexical: 0.16.0
checksum: 484b6c53dd62aa679f71c9f2b602463de8cf64974a4c6c7052798f1f995b2b8805f2da7a34895fcc73fdaa9938f7a3785ca92a954ba9d79c0c126c496551ad40
"@lexical/clipboard": 0.22.0
"@lexical/utils": 0.22.0
lexical: 0.22.0
checksum: 6a8e3564ef7431fd0928ac85fc0e2fb517c1d12a2464ed99a2738241aca53bd904bcf9d04ad434b6c9f0d086c5735173cd3ae4a7d25d3635c547d56a9b65dee6
languageName: node
linkType: hard
"@lexical/text@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/text@npm:0.16.0"
"@lexical/text@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/text@npm:0.22.0"
dependencies:
lexical: 0.16.0
checksum: 60eadf8d4c037af3a53dfb8c1168949529e02d1a7aaf31876eb9f0a790c4bc9b0c46747535fc03974c6a637e9a6dd0026d556bb0f61e918ad72e811987d08b65
lexical: 0.22.0
checksum: 82857b6c3b6cc4f2ad2264f9c3e87656f94bfaf4f879d538dd09ef1b7bb4eaade9b61001cf94618617baa7aebc14cdce00ce5d4687e2732171c3c33032e245eb
languageName: node
linkType: hard
"@lexical/utils@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/utils@npm:0.16.0"
"@lexical/utils@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/utils@npm:0.22.0"
dependencies:
"@lexical/list": 0.16.0
"@lexical/selection": 0.16.0
"@lexical/table": 0.16.0
lexical: 0.16.0
checksum: b6696b83b9ef7027cd7b117c25e6d6e30266f73b892e72e9718e02190b925c050f51b83aae25782c7abc950b6ef31d89e3c09ae3e37cae82274fcd42c5a60958
"@lexical/list": 0.22.0
"@lexical/selection": 0.22.0
"@lexical/table": 0.22.0
lexical: 0.22.0
checksum: 45e1e60f89e9dab45401db97ae1885260dad4436fefa1a2e752b7c3c1394322c3d28916c278e18c911a284676ab5cf850efb5cad2aa874281ee87a1ba31c409d
languageName: node
linkType: hard
"@lexical/yjs@npm:0.16.0":
version: 0.16.0
resolution: "@lexical/yjs@npm:0.16.0"
"@lexical/yjs@npm:0.22.0":
version: 0.22.0
resolution: "@lexical/yjs@npm:0.22.0"
dependencies:
"@lexical/offset": 0.16.0
lexical: 0.16.0
"@lexical/offset": 0.22.0
"@lexical/selection": 0.22.0
lexical: 0.22.0
peerDependencies:
yjs: ">=13.5.22"
checksum: 906056977928fa605593ee9fb323e37905960f97b7ef59ae20065f7644b51db72ddb8ef8ae1020c0a0b9bec9c2b18ed276c32ee5f4aabe4bc811cb8be102e9ac
checksum: 3ffe2fa446e542fd0af085ccbf015769ac65831977e3b3cbe3a37700442a7a042242d9cd2f27f078a4eaf09e76448c129a68aa05cc2b6808a813e0dee6b8de02
languageName: node
linkType: hard
@ -8338,13 +8330,13 @@ __metadata:
"@babel/plugin-transform-react-jsx": ^7.19.0
"@babel/preset-env": "*"
"@babel/preset-typescript": ^7.21.5
"@lexical/clipboard": 0.16.0
"@lexical/headless": 0.16.0
"@lexical/link": 0.16.0
"@lexical/list": 0.16.0
"@lexical/react": 0.16.0
"@lexical/rich-text": 0.16.0
"@lexical/utils": 0.16.0
"@lexical/clipboard": 0.22.0
"@lexical/headless": 0.22.0
"@lexical/link": 0.22.0
"@lexical/list": 0.22.0
"@lexical/react": 0.22.0
"@lexical/rich-text": 0.22.0
"@lexical/utils": 0.22.0
"@pmmmwh/react-refresh-webpack-plugin": ^0.5.10
"@radix-ui/react-slot": ^1.0.1
"@react-pdf/renderer": ^3.3.2
@ -8396,7 +8388,7 @@ __metadata:
identity-obj-proxy: ^3.0.0
jest: ^29.3.1
jest-environment-jsdom: ^29.3.1
lexical: 0.16.0
lexical: 0.22.0
lint-staged: ">=13"
mini-css-extract-plugin: ^2.7.2
minimatch: ^5.1.1
@ -19442,10 +19434,10 @@ __metadata:
languageName: node
linkType: hard
"lexical@npm:0.16.0":
version: 0.16.0
resolution: "lexical@npm:0.16.0"
checksum: ef43cf65dd30e044f7bbab1e56078b8ebee70a4182e517d1379c190d90174c04550c86921780360ad154fc78ce11cdd859bb0b8824971d072a38e0833166fe18
"lexical@npm:0.22.0":
version: 0.22.0
resolution: "lexical@npm:0.22.0"
checksum: 54153b6d31b007f45181317c6d18117c107dae90493f02f06b82c28488f266329431878c2ffe1af2df2638d3de363f5020d7a5019436531b220c3e1dea608938
languageName: node
linkType: hard