@37signals/lexxy 0.1.3-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +290 -0
- package/dist/lexxy.cjs.js +3138 -0
- package/dist/lexxy.esm.js +3136 -0
- package/dist/lexxy.min.js +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("lexical"),require("@lexical/list"),require("@lexical/rich-text"),require("@lexical/code"),require("@lexical/link"),require("@lexical/html"),require("@lexical/markdown"),require("@lexical/history"),require("dompurify"),require("@rails/activestorage"),require("marked"),require("prismjs/components/prism-ruby")):"function"==typeof define&&define.amd?define(["exports","lexical","@lexical/list","@lexical/rich-text","@lexical/code","@lexical/link","@lexical/html","@lexical/markdown","@lexical/history","dompurify","@rails/activestorage","marked","prismjs/components/prism-ruby"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Lexxy={},e.Lexical,e.LexicalList,e.LexicalRichText,e.LexicalCode,e.LexicalLink,e.LexicalHtml,e.LexicalMarkdown,e.LexicalHistory,e.DOMPurify,e.activestorage,e.marked)}(this,(function(e,t,i,n,s,o,r,a,l,c,d,h){"use strict";function u(e){let t=e;for(;null!==t;){if(i.$isListItemNode(t))return t;t=t.getParent()}return null}function g(e){let t=e;for(;t;){if(i.$isListNode(t))return t.getListType();t=t.getParent()}return null}class p extends HTMLElement{setEditor(e){this.editorElement=e,this.editor=e.editor,this.#e(),this.#t(),this.#i(),this.#n()}#e(){this.addEventListener("click",this.#s.bind(this))}#s({target:e}){this.#o(e,"[data-command]",this.#r.bind(this)),this.#o(e,"[data-dialog-target]",this.#a.bind(this))}#o(e,t,i){const n=e.closest(t);n&&i(n)}#r(e){const{command:t,payload:i}=e.dataset;this.editor.dispatchCommand(t,i)}#a(e){const t=document.getElementById(e.dataset.dialogTarget).parentNode;t.open?t.close():t.show()}#t(){this.editorElement.addEventListener("keydown",(e=>{this.querySelectorAll("[data-hotkey]").forEach((t=>{t.dataset.hotkey.toLowerCase().split(/\s+/).includes(this.#l(e))&&(e.preventDefault(),e.stopPropagation(),t.click())}))}))}#l(e){const t=e.key.toLowerCase();return[...[e.ctrlKey?"ctrl":null,e.metaKey?"cmd":null,e.altKey?"alt":null,e.shiftKey?"shift":null].filter(Boolean),t].join("+")}#i(){const e=parseInt(this.editorElement.editorContentElement.getAttribute("tabindex")??"0");this.querySelectorAll("button").forEach(((t,i)=>{t.setAttribute("tabindex",`${e+i+1}`)}))}#n(){this.editor.registerUpdateListener((()=>{this.editor.getEditorState().read((()=>{this.#c()}))}))}#c(){const e=t.$getSelection();if(!t.$isRangeSelection(e))return;const i=e.anchor.getNode();if(!i.getParent())return;const o=i.getTopLevelElementOrThrow(),r=e.hasFormat("bold"),a=e.hasFormat("italic"),l=s.$isCodeNode(o)||e.hasFormat("code"),c=this.#d(i),d=g(i),h=n.$isQuoteNode(o),u=n.$isHeadingNode(o),p=this.#h(i);this.#u("bold",r),this.#u("italic",a),this.#u("code",l),this.#u("unordered-list",c&&"bullet"===d),this.#u("ordered-list",c&&"number"===d),this.#u("quote",h),this.#u("heading",u),this.#u("link",p)}#g(e){return e.getNodes().some((e=>{if(s.$isCodeHighlightNode(e))return!0;if(t.$isTextNode(e)){const t=e.getParent();if(t&&s.$isCodeHighlightNode(t))return!0}return!1}))}#d(e){let t=e;for(;t;){if(i.$isListNode(t)||i.$isListItemNode(t))return!0;t=t.getParent()}return!1}#h(e){let t=e;for(;t;){if(o.$isLinkNode(t))return!0;t=t.getParent()}return!1}#u(e,t){const i=this.querySelector(`[name="${e}"]`);i&&i.setAttribute("aria-pressed",t.toString())}static get defaultTemplate(){return'\n <button type="button" name="bold" data-command="bold" title="Bold">\n <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="m4.1 23c-.5 0-.7-.4-.7-.7v-20.6c0-.4.4-.7.7-.7h8.9c2 0 3.8.6 4.9 1.5 1.2 1 1.8 2.4 1.8 4.1s-.9 3.2-2.3 4.1c-.2 0-.3.3-.3.5s0 .4.3.5c1.9.8 3.2 2.7 3.2 5s-.7 3.6-2.1 4.7-3.3 1.7-5.6 1.7h-8.8zm4.2-18.1v5.1h3c1.2 0 2-.3 2.7-.7.6-.5.9-1.1.9-1.9s-.3-1.4-.8-1.8-1.3-.6-2.3-.6-2.4 0-3.5 0zm0 8.5v5.8h3.7c1.3 0 2.2-.3 2.8-.7s.9-1.2.9-2.2-.4-1.7-1-2.1-1.7-.7-2.9-.7-2.4 0-3.5 0z" fill-rule="evenodd"/> </svg>\n </button>\n \n <button type="button" name="italic" data-command="italic" title="Italic">\n <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m18.3 1.7c-1.7.4-2.5 1.3-2.7 2.6l-2.4 15.6c-.2 1.1.5 2.1 1.6 2.4.2 0 .2.2.2.3v.7h-.1c0 .1-.2.3-.3.3h-9c-.2 0-.3-.1-.3-.3v-.7h.1c0-.1.1-.2.2-.2 1.7-.4 2.5-1.3 2.7-2.6l2.4-15.6c.2-1.1-.5-2.1-1.6-2.4-.2 0-.2-.2-.2-.3v-.7h.1c0-.1.2-.3.3-.3h9c.2 0 .3.1.3.3v.7h-.1c0 .1-.1.2-.2.2z" fill-rule="evenodd"/></svg>\n </button>\n \n <button type="button" name="link" title="Link" data-dialog-target="link-dialog" data-hotkey="cmd+k ctrl+k">\n <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m22.2 1.8c-1.1-1.2-2.5-1.8-4.3-1.8s-3.1.6-4.4 1.8l-4.4 4.4c-1.2 1.2-1.8 2.7-1.8 4.3s.6 3.1 1.8 4.3h.2c.2.3.5.4 1 .4.7 0 1.1-.3 1.2-.6.3-.3.4-.7.4-1.1s-.2-.8-.5-1.2c-.5-.5-.8-1.2-.8-1.9s.3-1.4.8-1.9l4.4-4.2c.6-.5 1.5-.8 2.1-.8s1.4.2 1.9.7.8 1.2.8 1.9-.3 1.4-.8 1.9l-2.6 2.2c-.3.3-.5.7-.5 1.2s.2.8.5 1.2c.8.6 1.7.6 2.4 0l2.6-2.2c2.4-2.4 2.4-6.1 0-8.5z"/><path d="m12.3 9.3c-.3.3-.5.8-.5 1.3 0 .4.2.8.5 1.1.5.5.8 1.2.8 1.9s-.3 1.4-.9 1.9l-4.4 4.4c-.4.4-1.2.7-1.8.7s-1.4-.2-1.9-.7-.8-1.2-.8-1.9.3-1.4.8-1.9l2.5-2.4c.7-.7.7-1.7 0-2.4-.8-.6-1.7-.6-2.4 0l-2.5 2.4c-1 1.1-1.7 2.6-1.7 4.2s.6 3.1 1.8 4.3c1.3 1.2 2.7 1.8 4.2 1.8s3.2-.7 4.3-1.8l4.4-4.4c2.4-2.4 2.4-6.1 0-8.6-.8-.6-1.7-.6-2.4 0z"/></svg>\n </button>\n <lexxy-link-dialog class="lexxy-link-dialog">\n <dialog id="link-dialog" closedby="any">\n <form method="dialog">\n <input type="url" placeholder="Enter a URL…" class="input" required>\n <div class="lexxy-dialog-actions">\n <button type="submit" class="btn" value="link">Link</button>\n <button type="button" class="btn" value="unlink">Unlink</button>\n </div>\n </form> \n </dialog> \n </lexxy-link-dialog>\n \n <button type="button" name="quote" data-command="insertQuoteBlock" title="Quote">\n <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"> <path d="m1.1 5.2c.6-.7 1.4-1.3 2.4-1.4 2.6-.4 4.2.4 5.3 1.9 2 2.3 1.9 5.1.6 7.6-1.3 2.4-4 4.6-7.2 5.1-.4 0-.7-.1-1-.4-.1-.3-.1-.7.3-1.1l1.1-1.1c.3-.4.6-.7.7-1.1s.3-.9 0-1.3c0-.4-.6-.7-1-1-1.2-.8-2.3-2.2-2.3-4.1.1-1.4.4-2.4 1.1-3.1z"/> <path d="m14.6 5.2c.6-.7 1.6-1.1 2.6-1.4 2.4-.4 4.2.4 5.3 1.9 2 2.3 1.9 5.1.6 7.6-1.3 2.4-4 4.6-7.2 5.1-.4 0-.7-.1-1-.4-.1-.3-.1-.7.3-1.1l1.1-1.1c.3-.4.6-.7.7-1.1s.3-.9 0-1.3c-.1-.4-.6-.7-1-1-1.3-.6-2.4-2-2.4-3.9s.4-2.6 1-3.3z"/> </svg>\n </button>\n \n <button type="button" name="heading" data-command="rotateHeadingFormat" title="Heading">\n <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m5.7 6.2v16.3h3.8v-16.3h5.7v-3.8h-15.2v3.8zm10.1 16.4h3.8v-8.8h4.4v-3.8h-12.6v3.8h4.4z" fill-rule="evenodd"/></svg>\n </button>\n \n <button type="button" name="code" data-command="insertCodeBlock" title="Code">\n <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"><path d="m8 4.7c-.6-.6-1.6-.6-2.4 0l-5.1 5.2c-.3.3-.5.7-.5 1.2s.2.9.5 1.2l5.1 5.1c.3.3.7.5 1.2.5s.9-.2 1.2-.5c.6-.6.6-1.7 0-2.4l-4-4 4-4c.6-.6.6-1.7 0-2.4z"/><path d="m23.5 9.9-5.1-5.1c-.6-.6-1.8-.6-2.4 0-.3.3-.5.7-.5 1.2s.2.9.5 1.2l4 4-4 4c-.3.3-.5.7-.5 1.2s.2.9.5 1.2c.3.2.7.4 1.1.4s.9-.2 1.2-.5l5.1-5.1c.3-.3.5-.7.5-1.2s-.2-.9-.5-1.2z"/></svg>\n </button>\n \n <button type="button" name="unordered-list" data-command="insertUnorderedList" title="Bullet list">\n <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"> <path d="m2.1 4.8c1.1 0 2.1-.9 2.1-2.1s-1-2-2.1-2-2.1.9-2.1 2.1.9 2 2.1 2zm4.1-2c0-.8.6-1.4 1.4-1.4h15.1c.7 0 1.3.6 1.3 1.4s-.6 1.4-1.4 1.4h-15.1c-.7 0-1.3-.7-1.3-1.4zm1.3 6.8c-.8 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4h15.1c.8 0 1.4-.6 1.4-1.4s-.6-1.4-1.4-1.4zm0 8.3c-.8 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4h15.1c.8 0 1.4-.6 1.4-1.4s-.6-1.4-1.4-1.4zm-3.4-6.9c0 1.1-.9 2.1-2.1 2.1s-2-1-2-2.1.9-2.1 2.1-2.1 2 1 2 2.1zm-2 10.3c1.1 0 2.1-.9 2.1-2.1s-.9-2.1-2.1-2.1-2.1 1-2.1 2.1.9 2.1 2.1 2.1z" fill-rule="evenodd"/> </svg> \n </button>\n \n <button type="button" name="ordered-list" data-command="insertOrderedList" title="Numbered list">\n <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"><path d="m6.7 3c0-.7.6-1.3 1.3-1.3h14.7c.7 0 1.3.6 1.3 1.3s-.6 1.3-1.3 1.3h-14.7c-.7 0-1.3-.6-1.3-1.3zm1.3 6.7c-.7 0-1.3.6-1.3 1.3s.6 1.3 1.3 1.3h14.7c.7 0 1.3-.6 1.3-1.3s-.6-1.3-1.3-1.3zm0 8c-.7 0-1.3.6-1.3 1.3s.6 1.3 1.3 1.3h14.7c.7 0 1.3-.6 1.3-1.3s-.6-1.3-1.3-1.3z" fill-rule="evenodd"/><path d="m1.5 19.6v-.9h.5c.4 0 .8-.3.8-.7s-.3-.7-.8-.7-.8.3-.8.7h-1.2c0-.9.8-1.6 2-1.6s2 .5 2 1.5-.4 1.1-1.1 1.2c.7 0 1.2.7 1.2 1.3 0 1.1-1.1 1.6-2.1 1.6s-2-.8-2-1.6h1.2c0 .4.4.7.8.7s.8-.3.8-.7-.3-.7-.8-.7h-.7.1zm0-9.7h-1.2c0-.9.7-1.7 2-1.7s2 .7 2 1.6-.5 1.2-.9 1.7l-1.1 1.2h2.1v1.1h-3.9v-.8l2-2c.3-.3.5-.7.5-1.1s-.3-.7-.7-.7-.7.3-.7.7h-.3zm1.7-4.4h-1.3v-4.3l-1.2.8v-1.2l1.3-.8h1.3v5.5z"/></svg>\n </button>\n \n <button type="button" name="upload" data-command="uploadAttachments" title="Upload file">\n <svg viewBox="0 0 24 20" xmlns="http://www.w3.org/2000/svg"> <path d="m22 20h-20c-1.1 0-2-.9-2-2.1v-15.8c0-1.2.9-2.1 2-2.1h20c1.1 0 2 .9 2 2.1v15.8c0 1.1-.9 2.1-2 2.1zm0-2.9v-14.5c0-.3-.2-.5-.5-.5h-19c-.3 0-.5.2-.5.5v14.5c0 .1.1.2.2.2s.2 0 .2-.1l2.2-3.3c.1-.2.3-.3.5-.3h.7l2.6-4c.1-.2.3-.3.5-.3h.7c.2 0 .4.1.5.3l5.3 8c0 .1.2.2.3.2h.3c.2 0 .4-.2.4-.4s0-.2 0-.2l-1.3-1.9c-.2-.2-.2-.6 0-.8l1.2-1.6c.1-.2.3-.3.5-.3h1.1c.2 0 .4 0 .5.3l3.2 4.4c0 .1.3.2.4 0 .2 0 .2 0 .2-.2zm-5.5-7.6c-1.4 0-2.5-1.2-2.5-2.6s1.1-2.6 2.5-2.6 2.5 1.2 2.5 2.6-1.1 2.6-2.5 2.6z" fill-rule="evenodd"/> </svg>\n </button>\n '}}customElements.define("lexxy-toolbar",p);var m={codeHighlight:{atrule:"code-token__attr",attr:"code-token__attr","attr-name":"code-token__attr","attr-value":"code-token__selector",boolean:"code-token__property",bold:"code-token__variable",builtin:"code-token__selector",cdata:"code-token__comment",char:"code-token__selector",class:"code-token__function","class-name":"code-token__function",color:"code-token__property",comment:"code-token__comment",constant:"code-token__property",coord:"code-token__property",decorator:"code-token__function",deleted:"code-token__property",doctype:"code-token__comment",entity:"code-token__operator",function:"code-token__function",hexcode:"code-token__property",important:"code-token__variable",inserted:"code-token__selector",italic:"code-token__comment",keyword:"code-token__attr",namespace:"code-token__variable",number:"code-token__property",operator:"code-token__operator",parameter:"code-token__variable",prolog:"code-token__comment",property:"code-token__property",punctuation:"code-token__punctuation",regex:"code-token__variable",script:"code-token__function",selector:"code-token__selector",string:"code-token__selector",style:"code-token__function",symbol:"code-token__property",tag:"code-token__property",title:"code-token__function",url:"code-token__operator",variable:"code-token__variable"}};function f(e){if(0===e)return"0 B";const t=Math.floor(Math.log(e)/Math.log(1024));return`${(e/Math.pow(1024,t)).toFixed(2)} ${["B","KB","MB","GB","TB","PB"][t]}`}const b=["img","video","audio","iframe","embed","object","picture","source","canvas","svg","math","form","input","textarea","select","button","code","blockquote"].join(","),y=["a","action-text-attachment","b","blockquote","br","code","em","figcaption","figure","h1","h2","h3","h4","h5","h6","i","img","li","ol","p","pre","q","strong","ul"],v=["alt","caption","class","content","content-type","contenteditable","data-direct-upload-id","data-sgid","filename","filesize","height","href","presentation","previewable","sgid","src","title","url","width"];function x(e,t){const i=document.createElement(e);for(const[e,n]of Object.entries(t||{}))e in i?i[e]=n:null!=n&&i.setAttribute(e,n);return i}function N(e){return(new DOMParser).parseFromString(e,"text/html")}function E(e,t,i){const n=new CustomEvent(t,{detail:i,bubbles:!0});e.dispatchEvent(n)}function C(e){return`${e}-${Math.random().toString(36).slice(2,10)}`}class S extends t.DecoratorNode{static getType(){return"action_text_attachment"}static clone(e){return new S({...e},e.__key)}static importJSON(e){return new S({...e})}static importDOM(){return{"action-text-attachment":e=>({conversion:()=>({node:new S({sgid:e.getAttribute("sgid"),src:e.getAttribute("url"),previewable:e.getAttribute("previewable"),altText:e.getAttribute("alt"),caption:e.getAttribute("caption"),contentType:e.getAttribute("content-type"),fileName:e.getAttribute("filename"),fileSize:e.getAttribute("filesize"),width:e.getAttribute("width"),height:e.getAttribute("height")})}),priority:1}),img:e=>({conversion:()=>({node:new S({src:e.getAttribute("src"),contentType:"image/*",width:e.getAttribute("width"),height:e.getAttribute("height")})}),priority:1})}}constructor({sgid:e,src:t,previewable:i,altText:n,caption:s,contentType:o,fileName:r,fileSize:a,width:l,height:c},d){super(d),this.sgid=e,this.src=t,this.previewable=i,this.altText=n||"",this.caption=s||"",this.contentType=o||"",this.fileName=r,this.fileSize=a,this.width=l,this.height=c}createDOM(){const e=this.createAttachmentFigure();return e.addEventListener("click",(t=>{this.#p(e)})),this.isPreviewableAttachment?(e.appendChild(this.#m()),e.appendChild(this.#f())):(e.appendChild(this.#b()),e.appendChild(this.#y())),e}updateDOM(){return!0}isInline(){return!1}exportDOM(){return{element:x("action-text-attachment",{sgid:this.sgid,previewable:this.previewable||null,url:this.src,alt:this.altText,caption:this.caption,"content-type":this.contentType,filename:this.fileName,filesize:this.fileSize,width:this.width,height:this.height,presentation:"gallery"})}}exportJSON(){return{type:"action_text_attachment",version:1,sgid:this.sgid,src:this.src,previewable:this.previewable,altText:this.altText,caption:this.caption,contentType:this.contentType,fileName:this.fileName,fileSize:this.fileSize,width:this.width,height:this.height}}decorate(){return null}createAttachmentFigure(){return e=this.contentType,t=this.isPreviewableAttachment,i=this.fileName,x("figure",{className:`attachment attachment--${t?"preview":"file"} attachment--${i?i.split(".").pop().toLowerCase():"unknown"}`,"data-content-type":e});var e,t,i}get#v(){return(e=this.contentType).startsWith("image/")&&!e.includes("svg");var e}get isPreviewableAttachment(){return this.#v||this.previewable}#m(){return x("img",{src:this.src,alt:this.altText,...this.#x})}get#x(){return this.width&&this.height?{width:this.width,height:this.height}:{}}#b(){return x("span",{className:"attachment__icon",textContent:`${this.fileName?this.fileName.split(".").pop().toLowerCase():"unknown"}`})}#y(){const e=x("figcaption",{className:"attachment__caption"}),t=x("strong",{className:"attachment__name",textContent:this.caption||this.fileName}),i=x("span",{className:"attachment__size",textContent:f(this.fileSize)});return e.appendChild(t),e.appendChild(i),e}#p(e){E(e,"lexxy:node-selected",{key:this.getKey()})}#f(){const e=x("figcaption",{className:"attachment__caption"}),t=x("input",{type:"text",class:"input",value:this.caption,placeholder:this.fileName});return t.addEventListener("focusin",(()=>t.placeholder="Add caption...")),t.addEventListener("blur",this.#N.bind(this)),t.addEventListener("keydown",this.#E.bind(this)),e.appendChild(t),e}#C(e){}#N(e){const t=e.target;t.placeholder=this.fileName,this.#S(t)}#S(e){E(e,"lexxy:node-invalidated",{key:this.getKey(),values:{caption:e.value}})}#E(e){"Enter"===e.key&&(this.#S(e.target),E(e.target,"lexxy:move-to-next-line"),e.preventDefault()),e.stopPropagation()}}class L extends S{static getType(){return"action_text_attachment_upload"}static clone(e){return new L({...e},e.__key)}constructor({file:e,uploadUrl:t,blobUrlTemplate:i,editor:n,progress:s},o){super({contentType:e.type},o),this.file=e,this.uploadUrl=t,this.blobUrlTemplate=i,this.src=null,this.editor=n,this.progress=s||0}createDOM(){const e=this.createAttachmentFigure();this.isPreviewableAttachment?e.appendChild(this.#m()):e.appendChild(this.#b()),e.appendChild(this.#L());const t=x("progress",{value:this.progress,max:100});return e.appendChild(t),this.#T(e).then((()=>this.#w(t,e))),e}exportDOM(){const e=document.createElement("img");return this.src&&(e.src=this.src),{element:e}}#m(){return x("img")}#b(){return x("span",{className:"attachment__icon",textContent:this.#_()})}#_(){return this.file.name.split(".").pop().toLowerCase()}#L(){const e=x("figcaption",{className:"attachment__caption"}),t=x("span",{className:"attachment__name",textContent:this.file.name||""}),i=x("span",{className:"attachment__size",textContent:f(this.file.size)});return e.appendChild(t),e.appendChild(i),e}#T(e){const t=e.querySelector("img");return t?async function(e,t){return new Promise((i=>{const n=new FileReader;t.addEventListener("load",(()=>{i(t)})),n.onload=e=>{t.src=e.target.result||null},n.readAsDataURL(e)}))}(this.file,t):Promise.resolve()}#w(e,t){const i=new d.DirectUpload(this.file,this.uploadUrl,this);i.delegate={directUploadWillStoreFileWithXHR:t=>{t.upload.addEventListener("progress",(t=>{this.editor.update((()=>{e.value=Math.round(t.loaded/t.total*100)}))}))}},i.create(((e,i)=>{e?this.#k(t):(this.src=this.blobUrlTemplate.replace(":signed_id",i.signed_id).replace(":filename",encodeURIComponent(i.filename)),this.#A(i,t).then((()=>{this.#P(t,i)})))}))}#k(e){e.innerHTML="",e.classList.add("attachment--error"),e.appendChild(x("div",{innerText:`Error uploading ${this.file?.name??"image"}`}))}async#P(e,i){this.editor.update((()=>{const n=e.querySelector("img"),s=t.$getNodeByKey(this.getKey());s&&s.replace(new S({sgid:i.attachable_sgid,src:i.previewable?i.url:this.src,altText:i.filename,contentType:i.content_type,fileName:i.filename,fileSize:i.byte_size,width:n?.naturalWidth,previewable:i.previewable,height:n?.naturalHeight}))}),{tag:t.HISTORY_MERGE_TAG})}async#A(e,t){return e.previewable?new Promise((i=>{this.editor.update((()=>{const n=this.#m();n.addEventListener("load",(()=>{i()})),n.src=e.url,t.insertBefore(n,t.firstChild)}))})):Promise.resolve()}}const T=["bold","rotateHeadingFormat","italic","link","unlink","insertUnorderedList","insertOrderedList","insertQuoteBlock","insertCodeBlock","uploadAttachments"];class w{static configureFor(e){new w(e)}constructor(e){this.editorElement=e,this.editor=e.editor,this.selection=e.selection,this.contents=e.contents,this.clipboard=e.clipboard,this.#I(),this.#O()}dispatchPaste(e){return this.clipboard.paste(e)}dispatchBold(){this.editor.dispatchCommand(t.FORMAT_TEXT_COMMAND,"bold")}dispatchItalic(){this.editor.dispatchCommand(t.FORMAT_TEXT_COMMAND,"italic")}dispatchLink(e){this.#$(e)}dispatchUnlink(){this.#$(null)}dispatchInsertUnorderedList(){const e=t.$getSelection().anchor.getNode();this.selection.isInsideList&&e&&"bullet"===g(e)?this.contents.unwrapSelectedListItems():this.editor.dispatchCommand(i.INSERT_UNORDERED_LIST_COMMAND,void 0)}dispatchInsertOrderedList(){const e=t.$getSelection().anchor.getNode();this.selection.isInsideList&&e&&"number"===g(e)?this.contents.unwrapSelectedListItems():this.editor.dispatchCommand(i.INSERT_ORDERED_LIST_COMMAND,void 0)}dispatchInsertQuoteBlock(){this.contents.toggleNodeWrappingAllSelectedLines((e=>n.$isQuoteNode(e)),(()=>n.$createQuoteNode()))}dispatchInsertCodeBlock(){this.editor.update((()=>{this.selection.hasSelectedWordsInSingleLine?this.editor.dispatchCommand(t.FORMAT_TEXT_COMMAND,"code"):this.contents.toggleNodeWrappingAllSelectedLines((e=>s.$isCodeNode(e)),(()=>new s.CodeNode("plain")))}))}dispatchRotateHeadingFormat(){this.editor.update((()=>{const e=t.$getSelection();if(!t.$isRangeSelection(e))return;const i=e.anchor.getNode().getTopLevelElementOrThrow();let s="h2";if(n.$isHeadingNode(i)){const e=i.getTag();s="h2"===e?"h3":"h3"===e?"h4":"h4"===e?null:"h2"}s?this.contents.insertNodeWrappingEachSelectedLine((()=>n.$createHeadingNode(s))):this.contents.removeFormattingFromSelectedLines()}))}dispatchUploadAttachments(){const e=x("input",{type:"file",multiple:!0,onchange:({target:e})=>{const t=Array.from(e.files);if(t.length)for(const e of t)this.contents.uploadFile(e)}});document.body.appendChild(e),e.click(),setTimeout((()=>e.remove()),1e3)}#I(){for(const t of T){const i=`dispatch${e=t,e.charAt(0).toUpperCase()+e.slice(1)}`;this.#M(t,0,this[i].bind(this))}var e;this.#M(t.PASTE_COMMAND,t.COMMAND_PRIORITY_LOW,this.dispatchPaste.bind(this))}#M(e,t,i){this.editor.registerCommand(e,i,t)}#$(e){this.editor.update((()=>{null===e?o.$toggleLink(null):o.$toggleLink(e)}))}#O(){this.editorElement.supportsAttachments&&(this.dragCounter=0,this.editor.getRootElement().addEventListener("dragover",this.#R.bind(this)),this.editor.getRootElement().addEventListener("drop",this.#F.bind(this)),this.editor.getRootElement().addEventListener("dragenter",this.#D.bind(this)),this.editor.getRootElement().addEventListener("dragleave",this.#B.bind(this)))}#D(e){this.dragCounter++,1===this.dragCounter&&this.editor.getRootElement().classList.add("lexxy-editor--drag-over")}#B(e){this.dragCounter--,0===this.dragCounter&&this.editor.getRootElement().classList.remove("lexxy-editor--drag-over")}#R(e){e.preventDefault()}#F(e){e.preventDefault(),this.dragCounter=0,this.editor.getRootElement().classList.remove("lexxy-editor--drag-over");const t=e.dataTransfer;if(!t)return;const i=Array.from(t.files);if(i.length){for(const e of i)this.contents.uploadFile(e);this.editor.focus()}}}function _(){return new Promise(requestAnimationFrame)}class k{constructor(e){this.editorElement=e,this.editor=this.editorElement.editor,this.previouslySelectedKeys=new Set,this.#H(),this.#U()}clear(){this.current=null}set current(e){t.$isNodeSelection(e)?(this._current=t.$getSelection(),this.#z()):this.editor.update((()=>{this.#z(),this._current=null}))}get current(){return this._current}get cursorPosition(){let e={x:0,y:0};return this.editor.getEditorState().read((()=>{const t=this.#K();if(!t)return;const i=this.#W(t);i&&(e=this.#q(i,t))})),e}placeCursorAtTheEnd(){this.editor.update((()=>{t.$getRoot().selectEnd()}))}get hasSelectedWordsInSingleLine(){const e=t.$getSelection();if(!t.$isRangeSelection(e))return!1;if(e.isCollapsed())return!1;const i=e.anchor.getNode(),n=e.focus.getNode();if(i.getTopLevelElement()!==n.getTopLevelElement())return!1;if(!i.getTopLevelElement())return!1;const s=e.getNodes();for(const e of s)if(t.$isLineBreakNode(e))return!1;return!0}get isInsideList(){const e=t.$getSelection();if(!t.$isRangeSelection(e))return!1;return null!==u(e.anchor.getNode())}get nodeAfterCursor(){const{anchorNode:e,offset:i}=this.#Y();return e?t.$isTextNode(e)?this.#V(e,i):t.$isElementNode(e)?this.#G(e,i):this.#j(e):null}get nodeBeforeCursor(){const{anchorNode:e,offset:i}=this.#Y();return e?t.$isTextNode(e)?this.#Q(e,i):t.$isElementNode(e)?this.#X(e,i):this.#J(e):null}get#Z(){return this.editorElement.contents}get#ee(){if(this._currentlySelectedKeys)return this._currentlySelectedKeys;if(this._currentlySelectedKeys=new Set,this.current)for(const e of this.current.getNodes())this._currentlySelectedKeys.add(e.getKey());return this._currentlySelectedKeys}#U(){this.editor.registerCommand(t.KEY_ARROW_LEFT_COMMAND,this.#te.bind(this),t.COMMAND_PRIORITY_LOW),this.editor.registerCommand(t.KEY_ARROW_UP_COMMAND,this.#te.bind(this),t.COMMAND_PRIORITY_LOW),this.editor.registerCommand(t.KEY_ARROW_RIGHT_COMMAND,this.#ie.bind(this),t.COMMAND_PRIORITY_LOW),this.editor.registerCommand(t.KEY_ARROW_DOWN_COMMAND,this.#ie.bind(this),t.COMMAND_PRIORITY_LOW),this.editor.registerCommand(t.KEY_DELETE_COMMAND,this.#ne.bind(this),t.COMMAND_PRIORITY_LOW),this.editor.registerCommand(t.KEY_BACKSPACE_COMMAND,this.#se.bind(this),t.COMMAND_PRIORITY_LOW),this.editor.registerCommand(t.SELECTION_CHANGE_COMMAND,(()=>{this.current=t.$getSelection()}),t.COMMAND_PRIORITY_LOW)}#H(){this.editor.getRootElement().addEventListener("lexxy:node-selected",(async e=>{await _();const{key:i}=e.detail;this.editor.update((()=>{const e=t.$getNodeByKey(i);if(e){const i=t.$createNodeSelection();i.add(e.getKey()),t.$setSelection(i)}this.editor.focus()}))})),this.editor.getRootElement().addEventListener("lexxy:move-to-next-line",(e=>{this.#oe()}))}#z(){this.#re(),this.#ae(),this.previouslySelectedKeys=this.#ee,this._currentlySelectedKeys=null}#re(){for(const e of this.previouslySelectedKeys)if(!this.#ee.has(e)){const t=this.editor.getElementByKey(e);t&&t.classList.remove("node--selected")}}#ae(){for(const e of this.#ee)if(!this.previouslySelectedKeys.has(e)){const t=this.editor.getElementByKey(e);t&&t.classList.add("node--selected")}}async#te(){this.current?await this.#le((e=>e.selectPrevious())):this.#ce(this.nodeBeforeCursor)}async#ie(){this.current?await this.#le((e=>e.selectNext(0,0))):this.#ce(this.nodeAfterCursor)}async#le(e){await _(),this.current&&this.editor.update((()=>{this.clear(),e(this.current.getNodes()[0]),this.editor.focus()}))}async#oe(){this.editor.update((()=>{const e=this.#de();e&&this.#he(e)}))}#de(){const e=t.$getSelection();return e?t.$isNodeSelection(e)?this.#ue(e):t.$isRangeSelection(e)?this.#ge(e):null:null}#ue(e){const t=e.getNodes();return t.length>0?t[0].getTopLevelElement():null}#ge(e){return e.anchor.getNode().getTopLevelElement()}#he(e){const t=e.getNextSibling();t?t.selectStart():this.#pe()}#pe(){const e=t.$getRoot(),i=t.$createParagraphNode();e.append(i),i.selectStart()}#ce(e){e&&e instanceof t.DecoratorNode&&this.editor.update((()=>{const i=t.$createNodeSelection();i.add(e.getKey()),t.$setSelection(i)}))}#ne(){const e=this.nodeAfterCursor;return e instanceof t.DecoratorNode?this.#ce(e):this.#Z.deleteSelectedNodes(),!0}#se(){const e=this.nodeBeforeCursor;return e instanceof t.DecoratorNode?this.#ce(e):this.#Z.deleteSelectedNodes(),!0}#K(){const e=t.$getSelection();if(!e||!e.isCollapsed())return null;const i=window.getSelection();return i&&0!==i.rangeCount?i.getRangeAt(0):null}#W(e){let t=e.getBoundingClientRect();if(this.#me(t)){const i=this.#fe(e);t=i.getBoundingClientRect(),this.#be(i),i.remove()}return t}#me(e){return 0===e.width&&0===e.height||0===e.top&&0===e.left}#fe(e){const t=this.#ye();return e.insertNode(t),t}#ye(){const e=document.createElement("span");return e.textContent="",e.style.display="inline-block",e.style.width="1px",e.style.height="1em",e.style.lineHeight="normal",e}#be(e){const t=window.getSelection();t.removeAllRanges();const i=document.createRange();i.setStartAfter(e),i.collapse(!0),t.addRange(i)}#q(e,t){const i=this.editor.getRootElement().getBoundingClientRect();let n=e.left-i.left,s=e.top-i.top;const o=this.#ve(t);return isNaN(o)||(s+=o),{x:n,y:s,fontSize:o}}#ve(e){const t=window.getSelection().anchorNode,i=this.#xe(t);if(i instanceof HTMLElement){const e=window.getComputedStyle(i);return parseFloat(e.fontSize)}return 0}#xe(e){return e?.nodeType===Node.TEXT_NODE?e.parentElement:e}#Y(){const e=t.$getSelection();if(!t.$isRangeSelection(e)||!e.isCollapsed())return{anchorNode:null,offset:0};const{anchor:i}=e;return{anchorNode:i.getNode(),offset:i.offset}}#V(e,t){return t===e.getTextContentSize()?this.#Ne(e):null}#Ne(e){if(e.getNextSibling()instanceof t.DecoratorNode)return e.getNextSibling();const i=e.getParent();return i?i.getNextSibling():null}#G(e,t){return t<e.getChildrenSize()?e.getChildAtIndex(t):this.#j(e)}#Q(e,t){return 0===t?this.#Ee(e):null}#Ee(e){if(e.getPreviousSibling()instanceof t.DecoratorNode)return e.getPreviousSibling();return e.getParent().getPreviousSibling()}#X(e,t){return t>0?e.getChildAtIndex(t-1):this.#J(e)}#j(e){let t=e;for(;t&&null==t.getNextSibling();)t=t.getParent();return t?t.getNextSibling():null}#J(e){let t=e;for(;t&&null==t.getPreviousSibling();)t=t.getParent();return t?t.getPreviousSibling():null}}class A{constructor(e){this.editorElement=e,this.editor=e.editor}insertHtml(e){this.editor.update((()=>{const i=t.$getSelection();if(!t.$isRangeSelection(i))return;const n=r.$generateNodesFromDOM(this.editor,N(e));i.insertNodes(n)}))}insertNodeWrappingEachSelectedLine(e){this.editor.update((()=>{const i=t.$getSelection();if(!t.$isRangeSelection(i))return;i.extract().forEach((t=>{if(!t.getParent())return;const i=t.getTopLevelElementOrThrow(),n=e();n.append(...i.getChildren()),i.replace(n)}))}))}toggleNodeWrappingAllSelectedLines(e,i){this.editor.update((()=>{const n=t.$getSelection();if(!t.$isRangeSelection(n))return;const s=n.anchor.getNode().getTopLevelElementOrThrow();e(s)?this.removeFormattingFromSelectedLines():this.insertNodeWrappingAllSelectedLines(i)}))}insertNodeWrappingAllSelectedLines(e){this.editor.update((()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(i.isCollapsed()?this.#Ce(i,e):this.#Se(i,e))}))}removeFormattingFromSelectedLines(){this.editor.update((()=>{const e=t.$getSelection();if(!t.$isRangeSelection(e))return;const i=e.anchor.getNode().getTopLevelElementOrThrow(),n=t.$createParagraphNode();n.append(...i.getChildren()),i.replace(n)}))}hasSelectedText(){let e=!1;return this.editor.read((()=>{const i=t.$getSelection();e=t.$isRangeSelection(i)&&!i.isCollapsed()})),e}hasSelectedWords(){let e=!1;return this.editor.update((()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(e=!i.isCollapsed()&&i.anchor.getNode().getTopLevelElement()===i.focus.getNode().getTopLevelElement())})),e}unwrapSelectedListItems(){this.editor.update((()=>{const e=t.$getSelection();if(!t.$isRangeSelection(e))return;const{listItems:i,parentLists:n}=this.#Le(e);if(i.size>0){const e=this.#Te(i);this.#we(n),this.#_e(e)}}))}createLinkWithSelectedText(e){this.hasSelectedText()&&this.editor.update((()=>{const i=t.$getSelection(),n=i.getTextContent(),s=o.$createLinkNode(e);s.append(t.$createTextNode(n)),i.insertNodes([s])}))}textBackUntil(e){let i="";return this.editor.getEditorState().read((()=>{const n=t.$getSelection();if(!n||!n.isCollapsed())return;const s=n.anchor,o=s.getNode();if(!t.$isTextNode(o))return;const r=o.getTextContent(),a=s.offset,l=r.slice(0,a),c=l.lastIndexOf(e);-1!==c&&(i=l.slice(c+e.length))})),i}containsTextBackUntil(e){let i=!1;return this.editor.getEditorState().read((()=>{const n=t.$getSelection();if(!n||!n.isCollapsed())return;const s=n.anchor,o=s.getNode();if(!t.$isTextNode(o))return;const r=o.getTextContent(),a=s.offset,l=r.slice(0,a);i=l.includes(e)})),i}replaceTextBackUntil(e,t){t=Array.isArray(t)?t:[t],this.editor.update((()=>{const{anchorNode:i,offset:n}=this.#ke();if(!i)return;const s=this.#Ae(i,n,e);-1!==s&&this.#Pe(i,n,s,t)}))}uploadFile(e){if(!this.editorElement.supportsAttachments)return void console.warn("This editor does not supports attachments (it's configured with [attachments=false])");const i=this.editorElement.directUploadUrl,n=this.editorElement.blobUrlTemplate;this.editor.update((()=>{const s=t.$getSelection(),o=s?.anchor.getNode(),r=o?.getTopLevelElement(),a=new L({file:e,uploadUrl:i,blobUrlTemplate:n,editor:this.editor});r&&t.$isParagraphNode(r)&&0===r.getChildrenSize()?r.replace(a):r&&t.$isElementNode(r)?r.insertAfter(a):t.$insertNodes([a])}),{tag:t.HISTORY_MERGE_TAG})}deleteSelectedNodes(){this.editor.update((()=>{if(t.$isNodeSelection(this.#Ie.current)){let e=!1;if(this.#Ie.current.getNodes().forEach((i=>{const n=i.getParent();i.remove(),"root"===n.getType()&&0===n.getChildrenSize()&&n.append(t.$createParagraphNode()),e=!0})),e)return this.#Ie.clear(),this.editor.focus(),!0}}))}get#Ie(){return this.editorElement.selection}#Ce(e,i){const n=e.anchor.getNode().getTopLevelElementOrThrow();if(n.getTextContent()){const e=i();e.append(...n.getChildren()),n.replace(e)}else t.$insertNodes([i()])}#Se(e,t){const i=this.#Oe(e);if(0===i.length)return;const{lineSet:n,nodesToDelete:s}=this.#$e(i);if(0===n.size)return;const o=this.#Me(t,n);this.#Re(e,o),this.#Fe(s)}#Oe(e){const i=e.extract().map((e=>this.#De(e))).filter(Boolean);return t.$setSelection(null),i}#De(e){return t.$isParagraphNode(e)?e:t.$isTextNode(e)&&e.getParent()&&t.$isParagraphNode(e.getParent())?e.getParent():null}#$e(e){const t=new Set,i=new Set;return e.forEach((e=>{const n=e.getTextContent();n&&n.split("\n").forEach((e=>{e.trim()&&t.add(e)})),i.add(e)})),{lineSet:t,nodesToDelete:i}}#Me(e,i){const n=e(),s=Array.from(i);return s.forEach(((e,i)=>{n.append(t.$createTextNode(e)),i<s.length-1&&n.append(t.$createLineBreakNode())})),n}#Re(e,t){const i=e.anchor.getNode().getParent();i&&i.replace(t)}#Fe(e){e.forEach((e=>e.remove()))}#Le(e){const t=e.getNodes(),n=new Set,s=new Set;for(const e of t){const t=u(e);if(t){n.add(t);const e=t.getParent();e&&i.$isListNode(e)&&s.add(e)}}return{listItems:n,parentLists:s}}#Te(e){const t=[];for(const i of e){const e=this.#Be(i);e&&t.push(e)}return t}#Be(e){const n=e.getParent();if(!n||!i.$isListNode(n))return null;const s=t.$createParagraphNode(),o=this.#He(e,s);return e.insertAfter(s),this.#Ue(s,o),e.remove(),s}#He(e,t){const n=[];return e.getChildren().forEach((e=>{i.$isListNode(e)?n.push(e):t.append(e)})),n}#Ue(e,t){t.forEach((t=>{e.insertAfter(t)}))}#we(e){for(const t of e)i.$isListNode(t)&&0===t.getChildrenSize()&&t.remove()}#_e(e){if(0===e.length)return;const t=e[0],i=e[e.length-1];1===e.length?t.selectEnd():this.#ze(t,i)}#ze(e,i){e.selectStart();const n=t.$getSelection();n&&t.$isRangeSelection(n)&&(n.anchor.set(e.getKey(),0,"element"),n.focus.set(i.getKey(),i.getChildrenSize(),"element"))}#ke(){const e=t.$getSelection();if(!e||!e.isCollapsed())return{anchorNode:null,offset:0};const i=e.anchor,n=i.getNode();return t.$isTextNode(n)?{anchorNode:n,offset:i.offset}:{anchorNode:null,offset:0}}#Ae(e,t,i){return e.getTextContent().slice(0,t).lastIndexOf(i)}#Pe(e,i,n,s){const o=e.getTextContent(),r=o.slice(0,n),a=o.slice(i),l=t.$createTextNode(r),c=t.$createTextNode(a||" ");e.replace(l);this.#Ke(l,s).insertAfter(c),this.#We(c.getParentOrThrow()),c.select(0,0)}#Ke(e,t){let i=e;for(const e of t)i.insertAfter(e),i=e;return i}#We(e){if(t.$isParagraphNode(e)&&!this.editorElement.isSingleLineMode){const i=e.getChildren(),n=i[i.length-1],s=i[i.length-2];t.$isTextNode(n)&&""===n.getTextContent()&&s&&!t.$isTextNode(s)&&e.append(t.$createLineBreakNode())}}}function P(e){return e.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"")}class I{constructor(e){this.editorElement=e,this.editor=e.editor,this.contents=e.contents}paste(e){const t=e.clipboardData;return!!t&&(this.#qe(t)?(this.#Ye(t),e.preventDefault(),!0):void this.#Ve(t))}#qe(e){const t=Array.from(e.types);return 1===t.length&&"text/plain"===t[0]}#Ye(e){e.items[0].getAsString((e=>{(function(e){try{return new URL(e),!0}catch(e){return!1}})(e)&&this.contents.hasSelectedText()?this.contents.createLinkWithSelectedText(e):this.#Ge(e)}))}#Ge(e){const t=h.marked(e);this.contents.insertHtml(t)}#Ve(e){this.editorElement.supportsAttachments&&this.#je((()=>{for(const t of e.items){const e=t.getAsFile();e&&this.contents.uploadFile(e)}}))}async#je(e){const t=window.scrollY,i=window.scrollX;e(),await _(),window.scrollTo(i,t),this.editor.focus()}}class O extends t.DecoratorNode{static getType(){return"custom_action_text_attachment"}static clone(e){return new O({...e},e.__key)}static importJSON(e){return new O({...e})}static importDOM(){return{"action-text-attachment":e=>{const i=e.getAttribute("content");return e.getAttribute("content")?{conversion:()=>{const n=[],s=e.previousSibling;return s&&s.nodeType===Node.TEXT_NODE&&/\s$/.test(s.textContent)&&n.push(t.$createTextNode(" ")),n.push(new O({sgid:e.getAttribute("sgid"),innerHtml:JSON.parse(i),contentType:e.getAttribute("content-type")})),n.push(t.$createTextNode(" ")),{node:n}},priority:2}:null}}}constructor({sgid:e,contentType:t,innerHtml:i},n){super(n),this.sgid=e,this.contentType=t||"application/vnd.actiontext.unknown",this.innerHtml=i}createDOM(){const e=x("action-text-attachment",{"content-type":this.contentType,"data-lexxy-decorator":!0});return e.addEventListener("click",(t=>{E(e,"lexxy:node-selected",{key:this.getKey()})})),e.insertAdjacentHTML("beforeend",this.innerHtml),e}updateDOM(){return!0}isInline(){return!0}exportDOM(){return{element:x("action-text-attachment",{sgid:this.sgid,content:JSON.stringify(this.innerHtml),"content-type":this.contentType})}}exportJSON(){return{type:"custom_action_text_attachment",version:1,sgid:this.sgid,contentType:this.contentType,innerHtml:this.innerHtml}}decorate(){return null}}class $ extends HTMLElement{static formAssociated=!0;static debug=!0;static commands=["bold","italic",""];static observedAttributes=["connected"];constructor(){super(),this.internals=this.attachInternals(),this.internals.role="textbox"}connectedCallback(){this.id??=C("lexxy-editor"),this.editor=this.#Qe(),this.contents=new A(this),this.selection=new k(this),this.clipboard=new I(this),w.configureFor(this),this.#Xe(),this.toggleAttribute("connected",!0),this.valueBeforeDisconnect=null}disconnectedCallback(){this.valueBeforeDisconnect=this.value,this.#Je()}attributeChangedCallback(e,t,i){"connected"===e&&this.isConnected&&null!=t&&t!==i&&requestAnimationFrame((()=>this.#Ze()))}get form(){return this.internals.form}get toolbarElement(){return this.#et?(this.toolbar=this.toolbar||this.#tt(),this.toolbar):null}get directUploadUrl(){return this.dataset.directUploadUrl}get blobUrlTemplate(){return this.dataset.blobUrlTemplate}get isSingleLineMode(){return this.hasAttribute("single-line")}get supportsAttachments(){return"false"!==this.getAttribute("attachments")}focus(){this.editor.focus()}get value(){return this.cachedValue||this.editor?.getEditorState().read((()=>{this.cachedValue=function(e){return c.sanitize(e,{ALLOWED_TAGS:y,ALLOWED_ATTR:v,SAFE_FOR_XML:!1})}(r.$generateHtmlFromNodes(this.editor,null))})),this.cachedValue}set value(e){this.editor.update((()=>{t.$addUpdateTag(t.SKIP_DOM_SELECTION_TAG);const i=t.$getRoot();i.clear(),i.append(...this.#it(e)),i.select(),this.#nt(),requestAnimationFrame((()=>this.editor?.update((()=>{}))))}))}#it(e){e||(e="<p></p>");return r.$generateNodesFromDOM(this.editor,N(`<div>${e}</div>`)).map((e=>{if("paragraph"===e.getType()&&1===e.getChildrenSize()){const i=e.getFirstChild();if(i instanceof t.DecoratorNode&&!i.isInline())return i}return e}))}#Xe(){this.#st(),this.#ot(),this.#rt(),this.#at(),this.#lt(),this.#ct(),this.#dt(),this.#ht()}#Qe(){this.editorContentElement=this.editorContentElement||this.#ut();const e=t.createEditor({namespace:"LexicalEditor",onError(e){throw e},theme:m,nodes:this.#gt});return e.setRootElement(this.editorContentElement),e}get#gt(){const e=[n.QuoteNode,n.HeadingNode,i.ListNode,i.ListItemNode,s.CodeNode,s.CodeHighlightNode,o.LinkNode,o.AutoLinkNode,O];return this.supportsAttachments&&e.push(S,L),e}#ut(){const e=x("div",{classList:"lexxy-editor__content",contenteditable:!0,placeholder:this.getAttribute("placeholder")});return e.id=`${this.id}-content`,this.appendChild(e),this.getAttribute("tabindex")?(this.editorContentElement.setAttribute("tabindex",this.getAttribute("tabindex")),this.removeAttribute("tabindex")):e.setAttribute("tabindex",0),e}set#pt(e){const t=void 0!==this.#pt&&this.#pt!==this.value;this.internals.setFormValue(e),this._internalFormValue=e,t&&function(e,t,i=null,n=!1){e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:i,cancelable:n}))}(this,"lexxy:change")}get#pt(){return this._internalFormValue}#dt(){const e=this.valueBeforeDisconnect||this.getAttribute("value")||"<p></p>";this.value=e}#ht(){document.addEventListener("turbo:before-cache",this.#mt)}#mt=e=>{this.#Je()};#st(){this.#ft(this.editor.registerUpdateListener((({editorState:e})=>{this.cachedValue=null,this.#pt=this.value,this.#nt()})))}#ft(e){this.unregisterHandlers=this.unregisterHandlers||[],this.unregisterHandlers.push(e)}#bt(){this.unregisterHandlers?.forEach((e=>{e()})),this.unregisterHandlers=null}#ot(){n.registerRichText(this.editor),l.registerHistory(this.editor,l.createEmptyHistoryState(),20),i.registerList(this.editor),this.#yt(),a.registerMarkdownShortcuts(this.editor,a.TRANSFORMERS)}#yt(){s.registerCodeHighlighting(this.editor),this.append(x("lexxy-code-language-picker"))}#rt(){this.editor.getRootElement().addEventListener("lexxy:node-invalidated",(e=>{const{key:i,values:n}=e.detail;this.editor.update((()=>{const e=t.$getNodeByKey(i);if(e instanceof S){const t=e.getWritable();Object.assign(t,n)}}))}))}#at(){this.editor.registerCommand(t.KEY_ENTER_COMMAND,(e=>(e.ctrlKey||e.metaKey||!!this.isSingleLineMode)&&(e.preventDefault(),!0)),t.COMMAND_PRIORITY_NORMAL)}#lt(){$.debug&&this.#ft(this.editor.registerUpdateListener((({editorState:e})=>{e.read((()=>{console.debug("HTML: ",this.value)}))})))}#ct(){this.#et&&this.toolbarElement.setEditor(this)}#tt(){const e=this.getAttribute("toolbar");return e?document.getElementById(e):this.#vt()}get#et(){return"false"!==this.getAttribute("toolbar")}#vt(){const e=x("lexxy-toolbar");return e.innerHTML=p.defaultTemplate,this.prepend(e),e}#nt(){this.classList.toggle("lexxy-editor--empty",this.#xt)}get#xt(){return!this.editorContentElement.textContent.trim()&&!this.editorContentElement.querySelector(b)}#Je(){this.#bt(),this.editorContentElement&&(this.editorContentElement.remove(),this.editorContentElement=null),this.contents=null,this.editor=null,this.toolbar&&(this.getAttribute("toolbar")||this.toolbar.remove(),this.toolbar=null),this.selection=null,document.removeEventListener("turbo:before-cache",this.#mt)}#Ze(){this.disconnectedCallback(),this.connectedCallback()}}customElements.define("lexxy-editor",$);class M extends HTMLElement{connectedCallback(){this.dialog=this.querySelector("dialog"),this.input=this.querySelector("input"),this.addEventListener("submit",this.#Nt.bind(this)),this.querySelector("[value='unlink']").addEventListener("click",this.#Et.bind(this)),this.addEventListener("keydown",this.#Ct.bind(this))}show(e){this.input.value=this.#St,this.dialog.show()}close(){this.dialog.close()}#Nt(e){const t=e.submitter?.value;this.#Lt.dispatchCommand(t,this.input.value)}#Et(e){this.#Lt.dispatchCommand("unlink"),this.close()}#Ct(e){"Escape"===e.key&&(e.stopPropagation(),this.close())}get#St(){let e="";return this.#Lt.getEditorState().read((()=>{const i=t.$getSelection();if(!t.$isRangeSelection(i))return;let n=i.getNodes()[0];for(;n&&n.getParent();){if(o.$isLinkNode(n)){e=n.getURL();break}n=n.getParent()}})),e}get#Lt(){return this.closest("lexxy-toolbar").editor}}customElements.define("lexxy-link-dialog",M);class R{async buildListItems(e=""){return Promise.resolve([])}promptItemFor(e){return null}buildListItemElementFor(e){const t=e.querySelector("template[type='menu']").content.cloneNode(!0),i=x("li",{role:"option",id:C("prompt-item"),tabindex:"0"});return i.classList.add("lexxy-prompt-menu__item"),i.appendChild(t),i}async loadPromptItemsFromUrl(e){try{const t=await fetch(e),i=N(await t.text()).querySelectorAll("lexxy-prompt-item");return Promise.resolve(Array.from(i))}catch(e){return Promise.reject(e)}}}class F extends R{async buildListItems(e=""){const t=await this.fetchPromptItems();return this.#Tt(t,e)}async fetchPromptItems(e){return Promise.resolve([])}promptItemFor(e){return this.promptItemByListItem.get(e)}#Tt(e,t){const i=[];return this.promptItemByListItem=new WeakMap,e.forEach((e=>{const n=e.getAttribute("search");if(!t||(s=t,P(n).includes(P(s)))){const t=this.buildListItemElementFor(e);this.promptItemByListItem.set(t,e),i.push(t)}var s})),i}}class D extends F{constructor(e){super(),this.inlinePromptItemElements=Array.from(e)}async fetchPromptItems(){return Promise.resolve(this.inlinePromptItemElements)}}class B extends F{constructor(e){super(),this.url=e,this.fetchPromptItems()}async fetchPromptItems(){return this.promptItems??=await this.loadPromptItemsFromUrl(this.url),Promise.resolve(this.promptItems)}}class H extends R{constructor(e){super(),this.baseURL=e,this.loadAndFilterListItems=function(e,t){let i;return(...n)=>(clearTimeout(i),new Promise(((s,o)=>{i=setTimeout((async()=>{try{const t=await e(...n);s(t)}catch(e){o(e)}}),t)})))}(this.fetchFilteredListItems.bind(this),200)}async buildListItems(e=""){return await this.loadAndFilterListItems(e)}promptItemFor(e){return this.promptItemByListItem.get(e)}async fetchFilteredListItems(e){const t=await this.loadPromptItemsFromUrl(this.#wt(e));return this.#Tt(t)}#wt(e){const t=new URL(this.baseURL,window.location.origin);return t.searchParams.append("filter",e),t.toString()}#Tt(e){const t=[];this.promptItemByListItem=new WeakMap;for(const i of e){const e=this.buildListItemElementFor(i);this.promptItemByListItem.set(e,i),t.push(e)}return t}}class U extends HTMLElement{constructor(){super(),this.keyListeners=[]}connectedCallback(){this.source=this.#_t(),this.#kt()}disconnectedCallback(){this.source=null,this.popoverElement=null}get name(){return this.getAttribute("name")}get trigger(){return this.getAttribute("trigger")}get supportsSpaceInSearches(){return this.hasAttribute("supports-space-in-searches")}get#At(){return!this.supportsSpaceInSearches}#_t(){const e=this.getAttribute("src");return e?this.hasAttribute("remote-filtering")?new H(e):new B(e):new D(this.querySelectorAll("lexxy-prompt-item"))}#kt(){const e=this.#Lt.registerUpdateListener((()=>{this.#Lt.read((()=>{const i=t.$getSelection();if(!i)return;let n;if(t.$isRangeSelection(i)?n=i.anchor.getNode():t.$isNodeSelection(i)&&([n]=i.getNodes()),n&&t.$isTextNode(n)){[...n.getTextContent().trim()].pop()===this.trigger&&(e(),this.#Pt())}}))}))}get#Lt(){return this.#It.editor}get#It(){return this.closest("lexxy-editor")}get#Ie(){return this.#It.selection}async#Pt(){this.popoverElement??=await this.#Ot(),await this.#$t(),this.#Mt(),this.popoverElement.classList.toggle("lexxy-prompt-menu--visible",!0),this.#Rt(),this.#It.addEventListener("keydown",this.#Ft),this.#It.addEventListener("lexxy:change",this.#$t),this.#Dt()}#Dt(){this.keyListeners.push(this.#Lt.registerCommand(t.KEY_ENTER_COMMAND,this.#Bt.bind(this),t.COMMAND_PRIORITY_HIGH)),this.keyListeners.push(this.#Lt.registerCommand(t.KEY_TAB_COMMAND,this.#Bt.bind(this),t.COMMAND_PRIORITY_HIGH)),this.#At&&this.keyListeners.push(this.#Lt.registerCommand(t.KEY_SPACE_COMMAND,this.#Bt.bind(this),t.COMMAND_PRIORITY_HIGH))}#Rt(){const e=this.#Ht[0];e&&this.#Ut(e)}get#Ht(){return Array.from(this.popoverElement.querySelectorAll(".lexxy-prompt-menu__item"))}#Ut(e){this.#zt(),e.toggleAttribute("aria-selected",!0),e.focus(),this.#It.focus(),this.#Kt.setAttribute("aria-controls",this.popoverElement.id),this.#Kt.setAttribute("aria-activedescendant",e.id),this.#Kt.setAttribute("aria-haspopup","listbox")}#zt(){this.#Ht.forEach((e=>{e.toggleAttribute("aria-selected",!1)})),this.#Kt.removeAttribute("aria-controls"),this.#Kt.removeAttribute("aria-activedescendant"),this.#Kt.removeAttribute("aria-haspopup")}#Mt(){const{x:e,y:t,fontSize:i}=this.#Ie.cursorPosition,n=this.#It.getBoundingClientRect(),s=this.#Kt.getBoundingClientRect().top-n.top;this.popoverElement.style.left=`${e}px`,this.popoverElement.style.top=`${t+s}px`,this.popoverElement.style.bottom="auto";this.popoverElement.getBoundingClientRect().bottom>window.innerHeight&&(this.popoverElement.style.bottom=`${t-s+i}px`,this.popoverElement.style.top="auto")}async#Wt(){this.#zt(),this.popoverElement.classList.toggle("lexxy-prompt-menu--visible",!1),this.#It.removeEventListener("lexxy:change",this.#$t),this.#It.removeEventListener("keydown",this.#Ft),this.#qt(),await _(),this.#kt()}#qt(){this.keyListeners.forEach((e=>e())),this.keyListeners=[]}#$t=async()=>{this.initialPrompt?this.initialPrompt=!1:this.#Yt.containsTextBackUntil(this.trigger)?await this.#Vt():this.#Wt()};async#Vt(){const e=this.#Yt.textBackUntil(this.trigger),t=await this.source.buildListItems(e);this.popoverElement.innerHTML="",t.length>0?this.#Gt(t):this.#jt(),this.#Rt()}#Gt(e){this.popoverElement.classList.remove("lexxy-prompt-menu--empty"),this.popoverElement.append(...e)}#jt(){this.popoverElement.classList.add("lexxy-prompt-menu--empty");const e=x("li",{innerHTML:this.#Qt});e.classList.add("lexxy-prompt-menu__item--empty"),this.popoverElement.append(e)}get#Qt(){return this.getAttribute("empty-results")||"Nothing found"}#Ft=e=>{"Escape"===e.key?(this.#Wt(),this.#It.focus(),e.stopPropagation()):"ArrowDown"===e.key?(this.#Xt(),e.preventDefault(),e.stopPropagation()):"ArrowUp"===e.key&&(this.#Jt(),e.preventDefault(),e.stopPropagation())};#Xt(){const e=this.#Zt+1;e<this.#Ht.length&&this.#Ut(this.#Ht[e])}#Jt(){const e=this.#Zt-1;e>=0&&this.#Ut(this.#Ht[e])}get#Zt(){return this.#Ht.findIndex((e=>e.hasAttribute("aria-selected")))}get#ei(){return this.#Ht[this.#Zt]}#Bt(e){return" "!==e.key&&e.preventDefault(),e.stopPropagation(),this.#ti(),!0}#ti(){this.#ii(),this.#Wt(),this.#It.focus()}#ii(){const e=this.source.promptItemFor(this.#ei);if(!e)return;const t=e.querySelector("template[type='editor']"),i=`${this.trigger}${this.#Yt.textBackUntil(this.trigger)}`;this.hasAttribute("insert-editable-text")?this.#ni(t,i):this.#si(e,t,i)}#ni(e,t){this.#Lt.update((()=>{const i=r.$generateNodesFromDOM(this.#Lt,N(`${e.innerHTML}`));this.#Yt.replaceTextBackUntil(t,i)}))}#si(e,t,i){this.#Lt.update((()=>{const n=new O({sgid:e.getAttribute("sgid"),contentType:`application/vnd.actiontext.${this.name}`,innerHtml:t.innerHTML});this.#Yt.replaceTextBackUntil(i,n)}))}get#Yt(){return this.#It.contents}get#Kt(){return this.#It.editorContentElement}async#Ot(){const e=x("ul",{role:"listbox",id:C("prompt-popover")});return e.classList.add("lexxy-prompt-menu"),e.style.position="absolute",e.append(...await this.source.buildListItems()),e.addEventListener("click",this.#oi),this.#It.appendChild(e),e}#oi=e=>{const t=e.target.closest(".lexxy-prompt-menu__item");t&&(this.#Ut(t),this.#ti())}}customElements.define("lexxy-prompt",U);class z extends HTMLElement{connectedCallback(){this.editorElement=this.closest("lexxy-editor"),this.editor=this.editorElement.editor,this.#ri(),this.#ai()}#ri(){this.languagePickerElement=this.#li(),this.languagePickerElement.addEventListener("change",(()=>{this.#ci(this.languagePickerElement.value)})),this.languagePickerElement.style.position="absolute",this.editorElement.appendChild(this.languagePickerElement)}#li(){const e=x("select",{hidden:!0,className:"lexxy-code-language-picker","aria-label":"Pick a language…",name:"lexxy-code-language"});for(const[t,i]of Object.entries(this.#di)){const n=document.createElement("option");n.value=t,n.textContent=i,e.appendChild(n)}return e}get#di(){const e={...s.CODE_LANGUAGE_FRIENDLY_NAME_MAP};e.ruby||(e.ruby="Ruby");const t=Object.entries(e).sort((([,e],[,t])=>e.localeCompare(t))),i=t.findIndex((([e])=>"plain"===e)),n=t.splice(i,1)[0];return Object.fromEntries([n,...t])}#ci(e){this.editor.update((()=>{const t=this.#hi();t&&t.setLanguage(e)}))}#ai(){this.editor.registerUpdateListener((()=>{this.editor.getEditorState().read((()=>{const e=this.#hi();e?this.#ui(e):this.#gi()}))}))}#hi(){const e=t.$getSelection();if(!t.$isRangeSelection(e))return null;const i=e.anchor.getNode(),n=i.getParent();return s.$isCodeNode(i)?i:s.$isCodeNode(n)?n:null}#ui(e){const t=e.getLanguage();this.#pi(t),this.#mi(),this.#fi(e)}#pi(e){if(this.languagePickerElement&&e){const t=s.normalizeCodeLang(e);this.languagePickerElement.value=t}}#fi(e){const t=this.editor.getElementByKey(e.getKey());if(!t)return;const i=t.getBoundingClientRect(),n=this.editorElement.getBoundingClientRect(),s=i.top-n.top;this.languagePickerElement.style.top=`${s}px`}#mi(){this.languagePickerElement.hidden=!1}#gi(){this.languagePickerElement.hidden=!0}}customElements.define("lexxy-code-language-picker",z),e.highlightAll=function(){document.querySelectorAll("pre[data-language]").forEach((e=>{!function(e){const t=e.getAttribute("data-language");let i=e.innerHTML.replace(/<br\s*\/?>/gi,"\n");const n=Prism.languages[t];if(!n)return;i=(new DOMParser).parseFromString(i,"text/html").body.textContent||"";const s=Prism.highlight(i,n,t),o=x("code",{"data-language":t,innerHTML:s});e.replaceWith(o)}(e)}))}}));
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@37signals/lexxy",
|
|
3
|
+
"version": "0.1.3-beta",
|
|
4
|
+
"description": "Lexxy - A modern rich text editor for Rails.",
|
|
5
|
+
"module": "dist/lexxy.esm.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": "./dist/lexxy.esm.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"repository": "https://github.com/basecamp/lexxy.git",
|
|
12
|
+
"author": "Jorge Manrubia <jorge@37signals.com>",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
16
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
17
|
+
"rollup": "^4.44.1",
|
|
18
|
+
"rollup-plugin-gzip": "^4.1.1"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "rollup -c",
|
|
22
|
+
"build:npm": "rollup -c rollup.config.npm.mjs",
|
|
23
|
+
"watch": "rollup -wc",
|
|
24
|
+
"prerelease": "yarn build:npm",
|
|
25
|
+
"release": "yarn build:npm && yarn publish"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@lexical/clipboard": "^0.32.1",
|
|
29
|
+
"@lexical/code": "^0.32.1",
|
|
30
|
+
"@lexical/history": "^0.32.1",
|
|
31
|
+
"@lexical/html": "^0.32.1",
|
|
32
|
+
"@lexical/link": "^0.32.1",
|
|
33
|
+
"@lexical/list": "^0.32.1",
|
|
34
|
+
"@lexical/markdown": "^0.32.1",
|
|
35
|
+
"@lexical/rich-text": "^0.32.1",
|
|
36
|
+
"@lexical/selection": "^0.32.1",
|
|
37
|
+
"@lexical/table": "^0.32.1",
|
|
38
|
+
"@lexical/utils": "^0.32.1",
|
|
39
|
+
"dompurify": "^3.2.6",
|
|
40
|
+
"marked": "^16.0.0",
|
|
41
|
+
"prismjs": "^1.30.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@rails/activestorage": "^7.0.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"@rails/activestorage": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|