UNPKG

@lexical/clipboard

Version:

This package provides the copy/paste functionality for Lexical.

10 lines (8 loc) 5.39 kB
/** * 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. * */ "use strict";var e=require("@lexical/html"),t=require("@lexical/selection"),n=require("@lexical/utils"),o=require("lexical");function i(e,...t){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",e);for(const e of t)o.append("v",e);throw n.search=o.toString(),Error(`Minified Lexical error #${e}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}function r(t,n=o.$getSelection()){return null==n&&i(166),o.$isRangeSelection(n)&&n.isCollapsed()||0===n.getNodes().length?"":e.$generateHtmlFromNodes(t,n)}function l(e,t=o.$getSelection()){return null==t&&i(166),o.$isRangeSelection(t)&&t.isCollapsed()||0===t.getNodes().length?null:JSON.stringify(c(e,t))}function s(e,t,n){e.dispatchCommand(o.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND,{nodes:t,selection:n})||(n.insertNodes(t),function(e){if(o.$isRangeSelection(e)&&e.isCollapsed()){const t=e.anchor;let n=null;const i=o.$caretFromPoint(t,"previous");if(i)if(o.$isTextPointCaret(i))n=i.origin;else{const e=o.$getCaretRange(i,o.$getChildCaret(o.$getRoot(),"next").getFlipped());for(const t of e){if(o.$isTextNode(t.origin)){n=t.origin;break}if(o.$isElementNode(t.origin)&&!t.origin.isInline())break}}if(n&&o.$isTextNode(n)){const t=n.getFormat(),o=n.getStyle();e.format===t&&e.style===o||(e.format=t,e.style=o,e.dirty=!0)}}}(n))}function a(e,n,r,l=[]){let s=null===n||r.isSelected(n);const c=o.$isElementNode(r)&&r.excludeFromCopy("html");let d=r;if(null!==n){let e=o.$cloneWithProperties(r);e=o.$isTextNode(e)&&null!==n?t.$sliceSelectedTextNodeContent(n,e):e,d=e}const u=o.$isElementNode(d)?d.getChildren():[],f=function(e){const t=e.exportJSON(),n=e.constructor;if(t.type!==n.getType()&&i(58,n.name),o.$isElementNode(e)){const e=t.children;Array.isArray(e)||i(59,n.name)}return t}(d);if(o.$isTextNode(d)){const e=d.__text;e.length>0?f.text=e:s=!1}for(let t=0;t<u.length;t++){const i=u[t],l=a(e,n,i,f.children);!s&&o.$isElementNode(r)&&l&&r.extractWithChild(i,n,"clone")&&(s=!0)}if(s&&!c)l.push(f);else if(Array.isArray(f.children))for(let e=0;e<f.children.length;e++){const t=f.children[e];l.push(t)}return s}function c(e,t){const n=[],i=o.$getRoot().getChildren();for(let o=0;o<i.length;o++){a(e,t,i[o],n)}return{namespace:e._config.namespace,nodes:n}}function d(e){const n=[];for(let i=0;i<e.length;i++){const r=e[i],l=o.$parseSerializedNode(r);o.$isTextNode(l)&&t.$addNodeStyle(l),n.push(l)}return n}let u=null;function f(e,t,n){if(void 0===n){const t=o.getDOMSelection(e._window);if(!t)return!1;const i=t.anchorNode,r=t.focusNode;if(null!==i&&null!==r&&!o.isSelectionWithinEditor(e,i,r))return!1;const l=o.$getSelection();if(null===l)return!1;n=g(l)}t.preventDefault();const i=t.clipboardData;return null!==i&&(x(i,n),!0)}const p=[["text/html",r],["application/x-lexical-editor",l]];function g(e=o.$getSelection()){const t={"text/plain":e?e.getTextContent():""};if(e){const n=o.$getEditor();for(const[o,i]of p){const r=i(n,e);null!==r&&(t[o]=r)}}return t}function x(e,t){for(const n in t){const o=t[n];void 0!==o&&e.setData(n,o)}}exports.$generateJSONFromSelectedNodes=c,exports.$generateNodesFromSerializedNodes=d,exports.$getClipboardDataFromSelection=g,exports.$getHtmlContent=r,exports.$getLexicalContent=l,exports.$insertDataTransferForPlainText=function(e,t){const n=e.getData("text/plain")||e.getData("text/uri-list");null!=n&&t.insertRawText(n)},exports.$insertDataTransferForRichText=function(t,n,i){const r=t.getData("application/x-lexical-editor");if(r)try{const e=JSON.parse(r);if(e.namespace===i._config.namespace&&Array.isArray(e.nodes)){return s(i,d(e.nodes),n)}}catch(e){}const l=t.getData("text/html"),a=t.getData("text/plain");if(l&&a!==l)try{const t=(new DOMParser).parseFromString(function(e){if(window.trustedTypes&&window.trustedTypes.createPolicy){return window.trustedTypes.createPolicy("lexical",{createHTML:e=>e}).createHTML(e)}return e}(l),"text/html");return s(i,e.$generateNodesFromDOM(i,t),n)}catch(e){}const c=a||t.getData("text/uri-list");if(null!=c)if(o.$isRangeSelection(n)){const e=c.split(/(\r?\n|\t)/);""===e[e.length-1]&&e.pop();for(let t=0;t<e.length;t++){const n=o.$getSelection();if(o.$isRangeSelection(n)){const i=e[t];"\n"===i||"\r\n"===i?n.insertParagraph():"\t"===i?n.insertNodes([o.$createTabNode()]):n.insertText(i)}}}else n.insertRawText(c)},exports.$insertGeneratedNodes=s,exports.copyToClipboard=async function(e,t,i){if(null!==u)return!1;if(null!==t)return new Promise(((n,o)=>{e.update((()=>{n(f(e,t,i))}))}));const r=e.getRootElement(),l=e._window||window,s=window.document,a=o.getDOMSelection(l);if(null===r||null===a)return!1;const c=s.createElement("span");c.style.cssText="position: fixed; top: -1000px;",c.append(s.createTextNode("#")),r.append(c);const d=new Range;return d.setStart(c,0),d.setEnd(c,1),a.removeAllRanges(),a.addRange(d),new Promise(((t,r)=>{const l=e.registerCommand(o.COPY_COMMAND,(o=>(n.objectKlassEquals(o,ClipboardEvent)&&(l(),null!==u&&(window.clearTimeout(u),u=null),t(f(e,o,i))),!0)),o.COMMAND_PRIORITY_CRITICAL);u=window.setTimeout((()=>{l(),u=null,t(!1)}),50),s.execCommand("copy"),c.remove()}))},exports.setLexicalClipboardDataTransfer=x;