plug-and-play-editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +20 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.mjs +561 -0
- package/dist/plug-and-play-editor.css +1 -0
- package/dist/react.cjs +1 -0
- package/dist/react.d.ts +48 -0
- package/dist/react.mjs +50 -0
- package/package.json +53 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class E{container;textArea;editorArea;toolbar;plugins=new Map;constructor(t,a=[]){const n=typeof t=="string"?document.querySelector(t):t;if(!n||n.tagName!=="TEXTAREA")throw new Error("Editor must be initialized on a <textarea> element.");this.textArea=n,this.container=document.createElement("div"),this.container.className="play-editor-container",this.toolbar=document.createElement("div"),this.toolbar.className="play-editor-toolbar",this.editorArea=document.createElement("div"),this.editorArea.className="play-editor-content",this.editorArea.contentEditable="true",this.editorArea.innerHTML=this.textArea.value,this.init(a)}init(t){this.textArea.style.display="none",this.textArea.parentNode?.insertBefore(this.container,this.textArea),this.container.appendChild(this.toolbar),this.container.appendChild(this.editorArea),this.editorArea.addEventListener("input",()=>{this.textArea.value=this.editorArea.innerHTML}),this.editorArea.addEventListener("keydown",a=>{a.key==="Tab"&&(a.preventDefault(),document.execCommand("insertHTML",!1," "),this.textArea.value=this.editorArea.innerHTML)}),t.forEach(a=>{this.plugins.set(a.name,a),a.init(this)})}exec(t,a=void 0){this.editorArea.focus(),document.execCommand(t,!1,a),this.textArea.value=this.editorArea.innerHTML}addToolbarButton(t,a,n){const o=document.createElement("button");return o.type="button",o.className="play-editor-btn",o.title=a,o.innerHTML=t,o.addEventListener("click",i=>{i.preventDefault(),n()}),this.toolbar.appendChild(o),o}addToolbarDivider(){const t=document.createElement("div");t.className="play-editor-divider",this.toolbar.appendChild(t)}getContent(){return this.editorArea.innerHTML}setContent(t){this.editorArea.innerHTML=t,this.textArea.value=t}}const c=e=>`<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${e}</svg>`,d={bold:c('<path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/>'),italic:c('<line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/>'),underline:c('<path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" y1="20" x2="20" y2="20"/>'),strikethrough:c('<path d="M16 4H9a3 3 0 0 0-2.83 4"/><path d="M14 12a4 4 0 0 1 0 8H6"/><line x1="4" y1="12" x2="20" y2="12"/>'),listUnordered:c('<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>'),listOrdered:c('<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'),indent:c('<polyline points="3 8 7 12 3 16"/><line x1="21" y1="12" x2="11" y2="12"/><line x1="21" y1="6" x2="11" y2="6"/><line x1="21" y1="18" x2="11" y2="18"/>'),outdent:c('<polyline points="7 8 3 12 7 16"/><line x1="21" y1="12" x2="11" y2="12"/><line x1="21" y1="6" x2="11" y2="6"/><line x1="21" y1="18" x2="11" y2="18"/>'),textColor:c('<path d="M4 20h16"/><path d="m6 16 6-12 6 12"/><path d="M8 12h8"/>'),highlighter:c('<path d="m9 11-6 6v3h9l3-3"/><path d="m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4"/>'),alignLeft:c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="15" y1="12" x2="3" y2="12"/><line x1="17" y1="18" x2="3" y2="18"/>'),alignCenter:c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="17" y1="12" x2="7" y2="12"/><line x1="19" y1="18" x2="5" y2="18"/>'),alignRight:c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="12" x2="9" y2="12"/><line x1="21" y1="18" x2="7" y2="18"/>'),alignJustify:c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="12" x2="3" y2="12"/><line x1="21" y1="18" x2="3" y2="18"/>'),ltr:c('<path d="M11 4h6"/><path d="M13 4v16"/><path d="M17 4v16"/><path d="M7 12 3 8l4-4"/>'),rtl:c('<path d="M10 4h6"/><path d="M12 4v16"/><path d="M16 4v16"/><path d="M6 8l4 4-4 4"/>'),link:c('<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>'),unlink:c('<path d="m18.84 12.25 1.72-1.71a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="m5.17 11.75-1.71 1.71a5 5 0 0 0 7.07 7.07l1.71-1.71"/><line x1="2" y1="2" x2="22" y2="22"/>'),image:c('<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>'),video:c('<polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>'),table:c('<path d="M12 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/>'),tableRowAdd:c('<path d="M3 3h18v6H3z"/><path d="M3 15h18v6H3z"/><path d="M12 15v6"/><path d="M12 3v6"/>'),tableColAdd:c('<path d="M3 3v18h6V3z"/><path d="M15 3v18h6V3z"/><path d="M15 12h6"/><path d="M3 12h6"/>'),chevronDown:c('<path d="M6 9l6 6 6-6"/>'),minus:c('<line x1="5" y1="12" x2="19" y2="12"/>'),fileBreak:c('<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M3 12h18"/>'),listTree:c('<path d="M21 12h-8"/><path d="M21 6H11"/><path d="M21 18h-8"/><path d="M3 6v4c0 1.1.9 2 2 2h3"/><path d="M3 10v6c0 1.1.9 2 2 2h3"/>'),imageUpload:c('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>'),atSign:c('<circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8"/>'),code:c('<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>'),braces:c('<path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1"/><path d="M16 3h1a2 2 0 0 1 2 2v5a2 2 0 0 1 2 2 2 2 0 0 1-2 2v5a2 2 0 0 1-2 2h-1"/>'),calendar:c('<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>'),clock:c('<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>'),smile:c('<circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/>')},k={name:"formatting",init(e){e.addToolbarButton(d.bold,"Bold",()=>{e.exec("bold")}),e.addToolbarButton(d.italic,"Italic",()=>{e.exec("italic")}),e.addToolbarButton(d.underline,"Underline",()=>{e.exec("underline")}),e.addToolbarButton(d.strikethrough,"Strikethrough",()=>{e.exec("strikeThrough")})}},R={name:"lists",init(e){e.addToolbarDivider(),e.addToolbarButton(d.listUnordered,"Unordered List",()=>{e.exec("insertUnorderedList")}),e.addToolbarButton(d.listOrdered,"Ordered List",()=>{e.exec("insertOrderedList")}),e.addToolbarButton(d.indent,"Indent",()=>{e.exec("indent")}),e.addToolbarButton(d.outdent,"Outdent",()=>{e.exec("outdent")})}},B={name:"color",init(e){e.addToolbarDivider();const t=(a,n,o)=>{const i=document.createElement("div");i.className="play-editor-color-picker",i.title=o;const s=document.createElement("input");s.type="color",s.value="#000000";const p=document.createElement("span");return p.innerHTML=n,i.appendChild(p),i.appendChild(s),s.addEventListener("input",h=>{const g=h.target;e.exec(a,g.value)}),e.toolbar.appendChild(i),i};t("foreColor",d.textColor,"Text Color"),t("hiliteColor",d.highlighter,"Background Color")}},H={name:"links",init(e){e.addToolbarDivider(),e.addToolbarButton(d.link,"Insert Link",()=>{const t=prompt("Enter the link URL:","https://");t&&(e.exec("createLink",t),e.editorArea.querySelectorAll("a").forEach(n=>{n.target||(n.target="_blank")}))}),e.addToolbarButton(d.unlink,"Unlink",()=>{e.exec("unlink")})}},N={name:"media",init(e){e.addToolbarDivider(),e.addToolbarButton(d.image,"Insert Image (URL)",()=>{const a=prompt("Enter image URL:","https://");a&&(e.exec("insertImage",a),e.editorArea.querySelectorAll("img").forEach(o=>{o.style.maxWidth||(o.style.maxWidth="100%",o.style.height="auto")}))});const t=document.createElement("input");t.type="file",t.accept="image/*",t.style.display="none",document.body.appendChild(t),e.addToolbarButton(d.imageUpload,"Upload Image",()=>{t.click()}),t.addEventListener("change",()=>{const a=t.files?.[0];if(!a)return;const n=new FileReader;n.onload=o=>{const i=o.target?.result;if(i){const s=document.createElement("img");s.src=i,s.style.maxWidth="100%",s.style.height="auto",s.style.borderRadius="6px",s.style.margin="0.5em 0",e.editorArea.focus();const p=window.getSelection();if(p&&p.rangeCount>0){const h=p.getRangeAt(0);h.deleteContents(),h.insertNode(s),h.setStartAfter(s),h.collapse(!0),p.removeAllRanges(),p.addRange(h)}else e.editorArea.appendChild(s);e.textArea.value=e.editorArea.innerHTML}},n.readAsDataURL(a),t.value=""}),e.addToolbarButton(d.video,"Insert Video/Media",()=>{const a=prompt("Enter iframe embed code:",'<iframe src="..."></iframe>');a&&e.exec("insertHTML",a)})}},S={name:"directionality",init(e){e.addToolbarDivider(),e.addToolbarButton(d.ltr,"Left to Right",()=>{const t=window.getSelection();if(!t||t.rangeCount===0)return;let n=t.getRangeAt(0).commonAncestorContainer;n.nodeType===Node.TEXT_NODE&&(n=n.parentNode);const o=n;o&&o!==e.editorArea?o.setAttribute("dir","ltr"):e.editorArea.setAttribute("dir","ltr")}),e.addToolbarButton(d.rtl,"Right to Left",()=>{const t=window.getSelection();if(!t||t.rangeCount===0)return;let n=t.getRangeAt(0).commonAncestorContainer;n.nodeType===Node.TEXT_NODE&&(n=n.parentNode);const o=n;o&&o!==e.editorArea?o.setAttribute("dir","rtl"):e.editorArea.setAttribute("dir","rtl")})}},D={name:"alignment",init(e){e.addToolbarDivider(),e.addToolbarButton(d.alignLeft,"Align Left",()=>{e.exec("justifyLeft")}),e.addToolbarButton(d.alignCenter,"Align Center",()=>{e.exec("justifyCenter")}),e.addToolbarButton(d.alignRight,"Align Right",()=>{e.exec("justifyRight")}),e.addToolbarButton(d.alignJustify,"Justify",()=>{e.exec("justifyFull")})}},P={name:"tables",init(e){e.addToolbarDivider(),e.addToolbarButton(d.table,"Insert 3x3 Table",()=>{let n='<table class="play-editor-table"><tbody>';for(let o=0;o<3;o++){n+="<tr>";for(let i=0;i<3;i++)n+="<td><br></td>";n+="</tr>"}n+="</tbody></table><p><br></p>",e.exec("insertHTML",n)}),e.addToolbarButton(d.tableRowAdd,"Add Row Below",()=>{const t=window.getSelection();if(!t||!t.rangeCount)return;let a=t.anchorNode;for(;a&&a!==e.editorArea&&a.nodeName!=="TR";)a=a.parentNode;if(a&&a.nodeName==="TR"){const n=a,o=n.children.length,i=document.createElement("tr");for(let s=0;s<o;s++){const p=document.createElement("td");p.innerHTML="<br>",i.appendChild(p)}n.parentNode?.insertBefore(i,n.nextSibling),e.textArea.value=e.editorArea.innerHTML}}),e.addToolbarButton(d.tableColAdd,"Add Col Right",()=>{const t=window.getSelection();if(!t||!t.rangeCount)return;let a=t.anchorNode;for(;a&&a!==e.editorArea&&a.nodeName!=="TD"&&a.nodeName!=="TH";)a=a.parentNode;if(a&&(a.nodeName==="TD"||a.nodeName==="TH")){const n=a,o=Array.from(n.parentNode.children).indexOf(n),i=n.closest("table");i&&(i.querySelectorAll("tr").forEach(p=>{const h=document.createElement(a.nodeName);h.innerHTML="<br>";const g=p.children[o];p.insertBefore(h,g.nextSibling)}),e.textArea.value=e.editorArea.innerHTML)}})}},I={name:"accordion",init(e){e.addToolbarButton(d.chevronDown,"Insert Accordion",()=>{e.exec("insertHTML",`
|
|
2
|
+
<details class="play-editor-accordion" open>
|
|
3
|
+
<summary class="play-editor-accordion-title">Click to expand</summary>
|
|
4
|
+
<div class="play-editor-accordion-content">
|
|
5
|
+
<p>Accordion content goes here...</p>
|
|
6
|
+
</div>
|
|
7
|
+
</details>
|
|
8
|
+
<p><br></p>
|
|
9
|
+
`)})}},O={name:"page-break",init(e){e.addToolbarDivider(),e.addToolbarButton(d.minus,"Horizontal Rule",()=>{e.exec("insertHorizontalRule")}),e.addToolbarButton(d.fileBreak,"Page Break",()=>{e.exec("insertHTML",`
|
|
10
|
+
<div class="play-editor-page-break" contenteditable="false">
|
|
11
|
+
<span>Page Break</span>
|
|
12
|
+
</div>
|
|
13
|
+
<p><br></p>
|
|
14
|
+
`)})}},U={name:"toc",init(e){e.addToolbarButton(d.listTree,"Insert Table of Contents",()=>{const t=e.editorArea.querySelectorAll("h1, h2, h3, h4, h5, h6");if(t.length===0){alert("No headings found to generate a Table of Contents.");return}let a='<div class="play-editor-toc" contenteditable="false"><h3>Table of Contents</h3><ul>';t.forEach((n,o)=>{const i=`toc-heading-${o}`;n.id=i;const p=(parseInt(n.tagName.charAt(1))-1)*20;a+=`<li style="margin-left: ${p}px"><a href="#${i}">${n.textContent}</a></li>`}),a+="</ul></div><p><br></p>",e.exec("insertHTML",a)})}},j={name:"paste-image",init(e){e.editorArea.addEventListener("paste",t=>{const a=t.clipboardData?.items;if(a)for(let n=0;n<a.length;n++){const o=a[n];if(o.type.startsWith("image/")){t.preventDefault();const i=o.getAsFile();if(!i)return;const s=new FileReader;s.onload=p=>{const h=p.target?.result;if(h){const g=document.createElement("img");g.src=h,g.style.maxWidth="100%",g.style.height="auto",g.style.borderRadius="6px",g.style.margin="0.5em 0";const l=window.getSelection();if(l&&l.rangeCount>0){const r=l.getRangeAt(0);r.deleteContents(),r.insertNode(g),r.setStartAfter(g),r.collapse(!0),l.removeAllRanges(),l.addRange(r)}else e.editorArea.appendChild(g);e.textArea.value=e.editorArea.innerHTML}},s.readAsDataURL(i);break}}})}},$=[];function L(e={}){const t=e.trigger||"@",a=e.users||$;return{name:"mentions",init(n){n.addToolbarDivider(),n.addToolbarButton(d.atSign,"Mention (@)",()=>{n.editorArea.focus(),n.exec("insertHTML",t),g()});let o=null;function i(){o&&(o.remove(),o=null)}function s(){const l=window.getSelection();if(!l||l.rangeCount===0)return null;const r=l.getRangeAt(0).cloneRange();r.collapse(!1);const m=document.createElement("span");m.textContent="โ",r.insertNode(m);const u=m.getBoundingClientRect(),x=n.editorArea.getBoundingClientRect(),y={top:u.bottom-x.top+n.editorArea.scrollTop,left:u.left-x.left};return m.remove(),l.getRangeAt(0).commonAncestorContainer.parentElement?.normalize(),y}function p(l){const r=window.getSelection();if(!r||r.rangeCount===0)return;const m=r.getRangeAt(0),u=m.startContainer;if(u.nodeType===Node.TEXT_NODE){const x=u.textContent||"",y=m.startOffset,v=x.lastIndexOf(t,y);if(v!==-1){const f=x.substring(0,v),w=x.substring(y);u.textContent=f;const b=document.createElement("span");b.className="play-editor-mention",b.contentEditable="false",b.dataset.userId=l.id,b.textContent=`@${l.name}`;const A=document.createTextNode("ย "+w),M=u.parentNode;M.insertBefore(b,u.nextSibling),M.insertBefore(A,b.nextSibling);const T=document.createRange();T.setStart(A,1),T.collapse(!0),r.removeAllRanges(),r.addRange(T)}}i(),n.textArea.value=n.editorArea.innerHTML}async function h(l){i();let r;if(typeof a=="function"){const u=a(l);r=u instanceof Promise?await u:u}else r=a.filter(u=>u.name.toLowerCase().includes(l.toLowerCase()));if(r.length===0)return;const m=s();m&&(o=document.createElement("div"),o.className="play-editor-mention-dropdown",o.style.top=`${m.top+4}px`,o.style.left=`${m.left}px`,r.slice(0,8).forEach((u,x)=>{const y=document.createElement("div");y.className="play-editor-mention-item",x===0&&y.classList.add("active");const v=u.name.split(" ").map(f=>f[0]).join("").toUpperCase();y.innerHTML=`
|
|
15
|
+
<div class="play-editor-mention-avatar">${u.avatar?`<img src="${u.avatar}" />`:v}</div>
|
|
16
|
+
<span class="play-editor-mention-name">${u.name}</span>
|
|
17
|
+
`,y.addEventListener("mousedown",f=>{f.preventDefault(),p(u)}),o.appendChild(y)}),n.editorArea.style.position="relative",n.editorArea.appendChild(o))}async function g(){const l=window.getSelection();if(!l||l.rangeCount===0){i();return}const r=l.getRangeAt(0),m=r.startContainer;if(m.nodeType!==Node.TEXT_NODE){i();return}const u=m.textContent||"",x=r.startOffset,y=u.substring(0,x),v=y.lastIndexOf(t);if(v===-1){i();return}const f=y.substring(v+t.length);if(f.includes(" ")&&f.trim().length>0){i();return}await h(f)}n.editorArea.addEventListener("input",g),n.editorArea.addEventListener("keydown",l=>{if(!o)return;const r=o.querySelectorAll(".play-editor-mention-item"),m=o.querySelector(".play-editor-mention-item.active");let u=Array.from(r).indexOf(m);l.key==="ArrowDown"?(l.preventDefault(),m?.classList.remove("active"),u=(u+1)%r.length,r[u].classList.add("active")):l.key==="ArrowUp"?(l.preventDefault(),m?.classList.remove("active"),u=(u-1+r.length)%r.length,r[u].classList.add("active")):l.key==="Enter"||l.key==="Tab"?m&&(l.preventDefault(),m.dispatchEvent(new MouseEvent("mousedown"))):l.key==="Escape"&&(l.preventDefault(),i())}),document.addEventListener("click",l=>{o&&!o.contains(l.target)&&i()})}}}const z=L(),q={name:"code-block",init(e){e.addToolbarDivider(),e.addToolbarButton(d.code,"Inline Code",()=>{const n=window.getSelection();if(!n||n.rangeCount===0)return;const o=n.getRangeAt(0),i=o.toString();if(i){const s=document.createElement("code");s.className="play-editor-inline-code",s.textContent=i,o.deleteContents(),o.insertNode(s),o.setStartAfter(s),o.collapse(!0),n.removeAllRanges(),n.addRange(o)}else{const s=document.createElement("code");s.className="play-editor-inline-code",s.innerHTML=" ",o.insertNode(s),o.selectNodeContents(s),n.removeAllRanges(),n.addRange(o)}e.textArea.value=e.editorArea.innerHTML}),e.addToolbarButton(d.braces,"Code Block",()=>{const o=window.getSelection()?.toString()||"// your code here",i=`
|
|
18
|
+
<pre class="play-editor-code-block"><code>${F(o)}</code></pre>
|
|
19
|
+
<p><br></p>
|
|
20
|
+
`;e.exec("insertHTML",i)});let t=!1;const a=e.addToolbarButton(d.code,"Toggle HTML Source",()=>{if(t=!t,t){const n=e.editorArea.innerHTML;e.editorArea.innerText=n,e.editorArea.classList.add("play-editor-source-view"),a.classList.add("play-editor-btn-active")}else{const n=e.editorArea.innerText;e.editorArea.innerHTML=n,e.editorArea.classList.remove("play-editor-source-view"),a.classList.remove("play-editor-btn-active"),e.textArea.value=e.editorArea.innerHTML}})}};function F(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}const _={name:"datetime",init(e){e.addToolbarDivider(),e.addToolbarButton(d.calendar,"Insert Date",()=>{const t=new Date,a=t.toLocaleDateString(void 0,{year:"numeric",month:"long",day:"numeric"});e.exec("insertHTML",`<time class="play-editor-datetime" datetime="${t.toISOString()}">${a}</time>`)}),e.addToolbarButton(d.clock,"Insert Time",()=>{const t=new Date,a=t.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit"});e.exec("insertHTML",`<time class="play-editor-datetime" datetime="${t.toISOString()}">${a}</time>`)})}},C={Smileys:["๐","๐","๐","๐","๐","๐
","๐คฃ","๐","๐","๐","๐","๐","๐ฅฐ","๐","๐คฉ","๐","๐","๐","๐","๐","๐","๐คช","๐","๐ค","๐ค","๐คญ","๐คซ","๐ค","๐ซก"],Gestures:["๐","๐","๐","๐","๐ค","๐","โ๏ธ","๐ค","๐ค","๐ค","๐","๐ค","๐","โ","๐๏ธ","๐","๐ช","๐ฆพ"],Hearts:["โค๏ธ","๐งก","๐","๐","๐","๐","๐ค","๐ค","๐ค","๐","โฃ๏ธ","๐","๐","๐","๐","๐","๐","๐"],Objects:["๐","๐","๐","๐","๐","๐ฅ","โญ","๐","๐ก","๐ฅ","โจ","๐ฏ","โ
","โ","โ ๏ธ","๐","๐","๐","๐","๐
","๐","๐"],Arrows:["โก๏ธ","โฌ
๏ธ","โฌ๏ธ","โฌ๏ธ","โ๏ธ","โ๏ธ","โ๏ธ","โ๏ธ","โ๏ธ","โ๏ธ","๐","๐"]},V={name:"emoji",init(e){let t=null;e.addToolbarButton(d.smile,"Insert Emoji",()=>{if(t){t.remove(),t=null;return}const a=window.getSelection();let n=null;a&&a.rangeCount>0&&(n=a.getRangeAt(0).cloneRange()),t=document.createElement("div"),t.className="play-editor-emoji-picker";const o=document.createElement("div");o.className="play-editor-emoji-tabs";const i=document.createElement("div");i.className="play-editor-emoji-grid";const s=Object.keys(C);function p(g){i.innerHTML="",C[g].forEach(l=>{const r=document.createElement("button");r.type="button",r.className="play-editor-emoji-item",r.textContent=l,r.addEventListener("mousedown",m=>{m.preventDefault(),e.editorArea.focus(),n&&(a?.removeAllRanges(),a?.addRange(n)),e.exec("insertHTML",l),a&&a.rangeCount>0&&(n=a.getRangeAt(0).cloneRange())}),i.appendChild(r)})}s.forEach((g,l)=>{const r=document.createElement("button");r.type="button",r.className="play-editor-emoji-tab",l===0&&r.classList.add("active"),r.textContent=g,r.addEventListener("mousedown",m=>{m.preventDefault(),o.querySelectorAll(".play-editor-emoji-tab").forEach(u=>u.classList.remove("active")),r.classList.add("active"),p(g)}),o.appendChild(r)}),t.appendChild(o),t.appendChild(i),e.container.style.position="relative",e.container.appendChild(t),p(s[0]);const h=g=>{t&&!t.contains(g.target)&&(t.remove(),t=null,document.removeEventListener("mousedown",h))};setTimeout(()=>document.addEventListener("mousedown",h),0)})}};exports.AccordionPlugin=I;exports.AlignmentPlugin=D;exports.CodeBlockPlugin=q;exports.ColorPlugin=B;exports.DateTimePlugin=_;exports.DirectionalityPlugin=S;exports.Editor=E;exports.EmojiPlugin=V;exports.FormattingPlugin=k;exports.LinksPlugin=H;exports.ListsPlugin=R;exports.MediaPlugin=N;exports.MentionsPlugin=z;exports.PageBreakPlugin=O;exports.PasteImagePlugin=j;exports.TablesPlugin=P;exports.TocPlugin=U;exports.createMentionsPlugin=L;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export declare const AccordionPlugin: Plugin_2;
|
|
2
|
+
|
|
3
|
+
export declare const AlignmentPlugin: Plugin_2;
|
|
4
|
+
|
|
5
|
+
export declare const CodeBlockPlugin: Plugin_2;
|
|
6
|
+
|
|
7
|
+
export declare const ColorPlugin: Plugin_2;
|
|
8
|
+
|
|
9
|
+
export declare function createMentionsPlugin(options?: MentionsPluginOptions): Plugin_2;
|
|
10
|
+
|
|
11
|
+
export declare const DateTimePlugin: Plugin_2;
|
|
12
|
+
|
|
13
|
+
export declare const DirectionalityPlugin: Plugin_2;
|
|
14
|
+
|
|
15
|
+
export declare class Editor {
|
|
16
|
+
container: HTMLElement;
|
|
17
|
+
textArea: HTMLTextAreaElement;
|
|
18
|
+
editorArea: HTMLDivElement;
|
|
19
|
+
toolbar: HTMLDivElement;
|
|
20
|
+
private plugins;
|
|
21
|
+
constructor(selector: string | HTMLTextAreaElement, plugins?: Plugin_2[]);
|
|
22
|
+
private init;
|
|
23
|
+
exec(command: string, value?: string | undefined): void;
|
|
24
|
+
addToolbarButton(iconHtml: string, tooltip: string, onClick: () => void): HTMLButtonElement;
|
|
25
|
+
addToolbarDivider(): void;
|
|
26
|
+
getContent(): string;
|
|
27
|
+
setContent(html: string): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export declare const EmojiPlugin: Plugin_2;
|
|
31
|
+
|
|
32
|
+
export declare const FormattingPlugin: Plugin_2;
|
|
33
|
+
|
|
34
|
+
export declare const LinksPlugin: Plugin_2;
|
|
35
|
+
|
|
36
|
+
export declare const ListsPlugin: Plugin_2;
|
|
37
|
+
|
|
38
|
+
export declare const MediaPlugin: Plugin_2;
|
|
39
|
+
|
|
40
|
+
export declare const MentionsPlugin: Plugin_2;
|
|
41
|
+
|
|
42
|
+
export declare interface MentionsPluginOptions {
|
|
43
|
+
/** Provide a list of users or a function that returns users filtered by query */
|
|
44
|
+
users?: MentionUser[] | ((query: string) => MentionUser[] | Promise<MentionUser[]>);
|
|
45
|
+
/** Character that triggers the mention dropdown (default: '@') */
|
|
46
|
+
trigger?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare interface MentionUser {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
avatar?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export declare const PageBreakPlugin: Plugin_2;
|
|
56
|
+
|
|
57
|
+
export declare const PasteImagePlugin: Plugin_2;
|
|
58
|
+
|
|
59
|
+
declare interface Plugin_2 {
|
|
60
|
+
name: string;
|
|
61
|
+
init(editor: Editor): void;
|
|
62
|
+
}
|
|
63
|
+
export { Plugin_2 as Plugin }
|
|
64
|
+
|
|
65
|
+
export declare const TablesPlugin: Plugin_2;
|
|
66
|
+
|
|
67
|
+
export declare const TocPlugin: Plugin_2;
|
|
68
|
+
|
|
69
|
+
export { }
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
class k {
|
|
2
|
+
container;
|
|
3
|
+
textArea;
|
|
4
|
+
editorArea;
|
|
5
|
+
toolbar;
|
|
6
|
+
plugins = /* @__PURE__ */ new Map();
|
|
7
|
+
constructor(t, a = []) {
|
|
8
|
+
const n = typeof t == "string" ? document.querySelector(t) : t;
|
|
9
|
+
if (!n || n.tagName !== "TEXTAREA")
|
|
10
|
+
throw new Error(
|
|
11
|
+
"Editor must be initialized on a <textarea> element."
|
|
12
|
+
);
|
|
13
|
+
this.textArea = n, this.container = document.createElement("div"), this.container.className = "play-editor-container", this.toolbar = document.createElement("div"), this.toolbar.className = "play-editor-toolbar", this.editorArea = document.createElement("div"), this.editorArea.className = "play-editor-content", this.editorArea.contentEditable = "true", this.editorArea.innerHTML = this.textArea.value, this.init(a);
|
|
14
|
+
}
|
|
15
|
+
init(t) {
|
|
16
|
+
this.textArea.style.display = "none", this.textArea.parentNode?.insertBefore(this.container, this.textArea), this.container.appendChild(this.toolbar), this.container.appendChild(this.editorArea), this.editorArea.addEventListener("input", () => {
|
|
17
|
+
this.textArea.value = this.editorArea.innerHTML;
|
|
18
|
+
}), this.editorArea.addEventListener("keydown", (a) => {
|
|
19
|
+
a.key === "Tab" && (a.preventDefault(), document.execCommand("insertHTML", !1, " "), this.textArea.value = this.editorArea.innerHTML);
|
|
20
|
+
}), t.forEach((a) => {
|
|
21
|
+
this.plugins.set(a.name, a), a.init(this);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
exec(t, a = void 0) {
|
|
25
|
+
this.editorArea.focus(), document.execCommand(t, !1, a), this.textArea.value = this.editorArea.innerHTML;
|
|
26
|
+
}
|
|
27
|
+
addToolbarButton(t, a, n) {
|
|
28
|
+
const o = document.createElement("button");
|
|
29
|
+
return o.type = "button", o.className = "play-editor-btn", o.title = a, o.innerHTML = t, o.addEventListener("click", (i) => {
|
|
30
|
+
i.preventDefault(), n();
|
|
31
|
+
}), this.toolbar.appendChild(o), o;
|
|
32
|
+
}
|
|
33
|
+
addToolbarDivider() {
|
|
34
|
+
const t = document.createElement("div");
|
|
35
|
+
t.className = "play-editor-divider", this.toolbar.appendChild(t);
|
|
36
|
+
}
|
|
37
|
+
getContent() {
|
|
38
|
+
return this.editorArea.innerHTML;
|
|
39
|
+
}
|
|
40
|
+
setContent(t) {
|
|
41
|
+
this.editorArea.innerHTML = t, this.textArea.value = t;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const c = (e) => `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${e}</svg>`, d = {
|
|
45
|
+
// Formatting
|
|
46
|
+
bold: c('<path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/>'),
|
|
47
|
+
italic: c('<line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/>'),
|
|
48
|
+
underline: c('<path d="M6 4v6a6 6 0 0 0 12 0V4"/><line x1="4" y1="20" x2="20" y2="20"/>'),
|
|
49
|
+
strikethrough: c('<path d="M16 4H9a3 3 0 0 0-2.83 4"/><path d="M14 12a4 4 0 0 1 0 8H6"/><line x1="4" y1="12" x2="20" y2="12"/>'),
|
|
50
|
+
// Lists
|
|
51
|
+
listUnordered: c('<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>'),
|
|
52
|
+
listOrdered: c('<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'),
|
|
53
|
+
indent: c('<polyline points="3 8 7 12 3 16"/><line x1="21" y1="12" x2="11" y2="12"/><line x1="21" y1="6" x2="11" y2="6"/><line x1="21" y1="18" x2="11" y2="18"/>'),
|
|
54
|
+
outdent: c('<polyline points="7 8 3 12 7 16"/><line x1="21" y1="12" x2="11" y2="12"/><line x1="21" y1="6" x2="11" y2="6"/><line x1="21" y1="18" x2="11" y2="18"/>'),
|
|
55
|
+
// Color
|
|
56
|
+
textColor: c('<path d="M4 20h16"/><path d="m6 16 6-12 6 12"/><path d="M8 12h8"/>'),
|
|
57
|
+
highlighter: c('<path d="m9 11-6 6v3h9l3-3"/><path d="m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4"/>'),
|
|
58
|
+
// Alignment
|
|
59
|
+
alignLeft: c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="15" y1="12" x2="3" y2="12"/><line x1="17" y1="18" x2="3" y2="18"/>'),
|
|
60
|
+
alignCenter: c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="17" y1="12" x2="7" y2="12"/><line x1="19" y1="18" x2="5" y2="18"/>'),
|
|
61
|
+
alignRight: c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="12" x2="9" y2="12"/><line x1="21" y1="18" x2="7" y2="18"/>'),
|
|
62
|
+
alignJustify: c('<line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="12" x2="3" y2="12"/><line x1="21" y1="18" x2="3" y2="18"/>'),
|
|
63
|
+
// Directionality
|
|
64
|
+
ltr: c('<path d="M11 4h6"/><path d="M13 4v16"/><path d="M17 4v16"/><path d="M7 12 3 8l4-4"/>'),
|
|
65
|
+
rtl: c('<path d="M10 4h6"/><path d="M12 4v16"/><path d="M16 4v16"/><path d="M6 8l4 4-4 4"/>'),
|
|
66
|
+
// Links
|
|
67
|
+
link: c('<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>'),
|
|
68
|
+
unlink: c('<path d="m18.84 12.25 1.72-1.71a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="m5.17 11.75-1.71 1.71a5 5 0 0 0 7.07 7.07l1.71-1.71"/><line x1="2" y1="2" x2="22" y2="22"/>'),
|
|
69
|
+
// Media
|
|
70
|
+
image: c('<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/>'),
|
|
71
|
+
video: c('<polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>'),
|
|
72
|
+
// Tables
|
|
73
|
+
table: c('<path d="M12 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/>'),
|
|
74
|
+
tableRowAdd: c('<path d="M3 3h18v6H3z"/><path d="M3 15h18v6H3z"/><path d="M12 15v6"/><path d="M12 3v6"/>'),
|
|
75
|
+
tableColAdd: c('<path d="M3 3v18h6V3z"/><path d="M15 3v18h6V3z"/><path d="M15 12h6"/><path d="M3 12h6"/>'),
|
|
76
|
+
// Accordion
|
|
77
|
+
chevronDown: c('<path d="M6 9l6 6 6-6"/>'),
|
|
78
|
+
// Page Break / HR
|
|
79
|
+
minus: c('<line x1="5" y1="12" x2="19" y2="12"/>'),
|
|
80
|
+
fileBreak: c('<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M3 12h18"/>'),
|
|
81
|
+
// TOC
|
|
82
|
+
listTree: c('<path d="M21 12h-8"/><path d="M21 6H11"/><path d="M21 18h-8"/><path d="M3 6v4c0 1.1.9 2 2 2h3"/><path d="M3 10v6c0 1.1.9 2 2 2h3"/>'),
|
|
83
|
+
// Upload / File select
|
|
84
|
+
imageUpload: c('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>'),
|
|
85
|
+
// Mentions
|
|
86
|
+
atSign: c('<circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8"/>'),
|
|
87
|
+
// Code
|
|
88
|
+
code: c('<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>'),
|
|
89
|
+
braces: c('<path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1"/><path d="M16 3h1a2 2 0 0 1 2 2v5a2 2 0 0 1 2 2 2 2 0 0 1-2 2v5a2 2 0 0 1-2 2h-1"/>'),
|
|
90
|
+
// Date/Time
|
|
91
|
+
calendar: c('<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>'),
|
|
92
|
+
clock: c('<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>'),
|
|
93
|
+
// Emoji
|
|
94
|
+
smile: c('<circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/>')
|
|
95
|
+
}, B = {
|
|
96
|
+
name: "formatting",
|
|
97
|
+
init(e) {
|
|
98
|
+
e.addToolbarButton(d.bold, "Bold", () => {
|
|
99
|
+
e.exec("bold");
|
|
100
|
+
}), e.addToolbarButton(d.italic, "Italic", () => {
|
|
101
|
+
e.exec("italic");
|
|
102
|
+
}), e.addToolbarButton(d.underline, "Underline", () => {
|
|
103
|
+
e.exec("underline");
|
|
104
|
+
}), e.addToolbarButton(d.strikethrough, "Strikethrough", () => {
|
|
105
|
+
e.exec("strikeThrough");
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}, H = {
|
|
109
|
+
name: "lists",
|
|
110
|
+
init(e) {
|
|
111
|
+
e.addToolbarDivider(), e.addToolbarButton(d.listUnordered, "Unordered List", () => {
|
|
112
|
+
e.exec("insertUnorderedList");
|
|
113
|
+
}), e.addToolbarButton(d.listOrdered, "Ordered List", () => {
|
|
114
|
+
e.exec("insertOrderedList");
|
|
115
|
+
}), e.addToolbarButton(d.indent, "Indent", () => {
|
|
116
|
+
e.exec("indent");
|
|
117
|
+
}), e.addToolbarButton(d.outdent, "Outdent", () => {
|
|
118
|
+
e.exec("outdent");
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}, N = {
|
|
122
|
+
name: "color",
|
|
123
|
+
init(e) {
|
|
124
|
+
e.addToolbarDivider();
|
|
125
|
+
const t = (a, n, o) => {
|
|
126
|
+
const i = document.createElement("div");
|
|
127
|
+
i.className = "play-editor-color-picker", i.title = o;
|
|
128
|
+
const s = document.createElement("input");
|
|
129
|
+
s.type = "color", s.value = "#000000";
|
|
130
|
+
const p = document.createElement("span");
|
|
131
|
+
return p.innerHTML = n, i.appendChild(p), i.appendChild(s), s.addEventListener("input", (g) => {
|
|
132
|
+
const h = g.target;
|
|
133
|
+
e.exec(a, h.value);
|
|
134
|
+
}), e.toolbar.appendChild(i), i;
|
|
135
|
+
};
|
|
136
|
+
t("foreColor", d.textColor, "Text Color"), t("hiliteColor", d.highlighter, "Background Color");
|
|
137
|
+
}
|
|
138
|
+
}, S = {
|
|
139
|
+
name: "links",
|
|
140
|
+
init(e) {
|
|
141
|
+
e.addToolbarDivider(), e.addToolbarButton(d.link, "Insert Link", () => {
|
|
142
|
+
const t = prompt("Enter the link URL:", "https://");
|
|
143
|
+
t && (e.exec("createLink", t), e.editorArea.querySelectorAll("a").forEach((n) => {
|
|
144
|
+
n.target || (n.target = "_blank");
|
|
145
|
+
}));
|
|
146
|
+
}), e.addToolbarButton(d.unlink, "Unlink", () => {
|
|
147
|
+
e.exec("unlink");
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, D = {
|
|
151
|
+
name: "media",
|
|
152
|
+
init(e) {
|
|
153
|
+
e.addToolbarDivider(), e.addToolbarButton(d.image, "Insert Image (URL)", () => {
|
|
154
|
+
const a = prompt("Enter image URL:", "https://");
|
|
155
|
+
a && (e.exec("insertImage", a), e.editorArea.querySelectorAll("img").forEach((o) => {
|
|
156
|
+
o.style.maxWidth || (o.style.maxWidth = "100%", o.style.height = "auto");
|
|
157
|
+
}));
|
|
158
|
+
});
|
|
159
|
+
const t = document.createElement("input");
|
|
160
|
+
t.type = "file", t.accept = "image/*", t.style.display = "none", document.body.appendChild(t), e.addToolbarButton(d.imageUpload, "Upload Image", () => {
|
|
161
|
+
t.click();
|
|
162
|
+
}), t.addEventListener("change", () => {
|
|
163
|
+
const a = t.files?.[0];
|
|
164
|
+
if (!a) return;
|
|
165
|
+
const n = new FileReader();
|
|
166
|
+
n.onload = (o) => {
|
|
167
|
+
const i = o.target?.result;
|
|
168
|
+
if (i) {
|
|
169
|
+
const s = document.createElement("img");
|
|
170
|
+
s.src = i, s.style.maxWidth = "100%", s.style.height = "auto", s.style.borderRadius = "6px", s.style.margin = "0.5em 0", e.editorArea.focus();
|
|
171
|
+
const p = window.getSelection();
|
|
172
|
+
if (p && p.rangeCount > 0) {
|
|
173
|
+
const g = p.getRangeAt(0);
|
|
174
|
+
g.deleteContents(), g.insertNode(s), g.setStartAfter(s), g.collapse(!0), p.removeAllRanges(), p.addRange(g);
|
|
175
|
+
} else
|
|
176
|
+
e.editorArea.appendChild(s);
|
|
177
|
+
e.textArea.value = e.editorArea.innerHTML;
|
|
178
|
+
}
|
|
179
|
+
}, n.readAsDataURL(a), t.value = "";
|
|
180
|
+
}), e.addToolbarButton(d.video, "Insert Video/Media", () => {
|
|
181
|
+
const a = prompt("Enter iframe embed code:", '<iframe src="..."></iframe>');
|
|
182
|
+
a && e.exec("insertHTML", a);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}, I = {
|
|
186
|
+
name: "directionality",
|
|
187
|
+
init(e) {
|
|
188
|
+
e.addToolbarDivider(), e.addToolbarButton(d.ltr, "Left to Right", () => {
|
|
189
|
+
const t = window.getSelection();
|
|
190
|
+
if (!t || t.rangeCount === 0) return;
|
|
191
|
+
let n = t.getRangeAt(0).commonAncestorContainer;
|
|
192
|
+
n.nodeType === Node.TEXT_NODE && (n = n.parentNode);
|
|
193
|
+
const o = n;
|
|
194
|
+
o && o !== e.editorArea ? o.setAttribute("dir", "ltr") : e.editorArea.setAttribute("dir", "ltr");
|
|
195
|
+
}), e.addToolbarButton(d.rtl, "Right to Left", () => {
|
|
196
|
+
const t = window.getSelection();
|
|
197
|
+
if (!t || t.rangeCount === 0) return;
|
|
198
|
+
let n = t.getRangeAt(0).commonAncestorContainer;
|
|
199
|
+
n.nodeType === Node.TEXT_NODE && (n = n.parentNode);
|
|
200
|
+
const o = n;
|
|
201
|
+
o && o !== e.editorArea ? o.setAttribute("dir", "rtl") : e.editorArea.setAttribute("dir", "rtl");
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}, P = {
|
|
205
|
+
name: "alignment",
|
|
206
|
+
init(e) {
|
|
207
|
+
e.addToolbarDivider(), e.addToolbarButton(d.alignLeft, "Align Left", () => {
|
|
208
|
+
e.exec("justifyLeft");
|
|
209
|
+
}), e.addToolbarButton(d.alignCenter, "Align Center", () => {
|
|
210
|
+
e.exec("justifyCenter");
|
|
211
|
+
}), e.addToolbarButton(d.alignRight, "Align Right", () => {
|
|
212
|
+
e.exec("justifyRight");
|
|
213
|
+
}), e.addToolbarButton(d.alignJustify, "Justify", () => {
|
|
214
|
+
e.exec("justifyFull");
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}, O = {
|
|
218
|
+
name: "tables",
|
|
219
|
+
init(e) {
|
|
220
|
+
e.addToolbarDivider(), e.addToolbarButton(d.table, "Insert 3x3 Table", () => {
|
|
221
|
+
let n = '<table class="play-editor-table"><tbody>';
|
|
222
|
+
for (let o = 0; o < 3; o++) {
|
|
223
|
+
n += "<tr>";
|
|
224
|
+
for (let i = 0; i < 3; i++)
|
|
225
|
+
n += "<td><br></td>";
|
|
226
|
+
n += "</tr>";
|
|
227
|
+
}
|
|
228
|
+
n += "</tbody></table><p><br></p>", e.exec("insertHTML", n);
|
|
229
|
+
}), e.addToolbarButton(d.tableRowAdd, "Add Row Below", () => {
|
|
230
|
+
const t = window.getSelection();
|
|
231
|
+
if (!t || !t.rangeCount) return;
|
|
232
|
+
let a = t.anchorNode;
|
|
233
|
+
for (; a && a !== e.editorArea && a.nodeName !== "TR"; )
|
|
234
|
+
a = a.parentNode;
|
|
235
|
+
if (a && a.nodeName === "TR") {
|
|
236
|
+
const n = a, o = n.children.length, i = document.createElement("tr");
|
|
237
|
+
for (let s = 0; s < o; s++) {
|
|
238
|
+
const p = document.createElement("td");
|
|
239
|
+
p.innerHTML = "<br>", i.appendChild(p);
|
|
240
|
+
}
|
|
241
|
+
n.parentNode?.insertBefore(i, n.nextSibling), e.textArea.value = e.editorArea.innerHTML;
|
|
242
|
+
}
|
|
243
|
+
}), e.addToolbarButton(d.tableColAdd, "Add Col Right", () => {
|
|
244
|
+
const t = window.getSelection();
|
|
245
|
+
if (!t || !t.rangeCount) return;
|
|
246
|
+
let a = t.anchorNode;
|
|
247
|
+
for (; a && a !== e.editorArea && a.nodeName !== "TD" && a.nodeName !== "TH"; )
|
|
248
|
+
a = a.parentNode;
|
|
249
|
+
if (a && (a.nodeName === "TD" || a.nodeName === "TH")) {
|
|
250
|
+
const n = a, o = Array.from(n.parentNode.children).indexOf(n), i = n.closest("table");
|
|
251
|
+
i && (i.querySelectorAll("tr").forEach((p) => {
|
|
252
|
+
const g = document.createElement(a.nodeName);
|
|
253
|
+
g.innerHTML = "<br>";
|
|
254
|
+
const h = p.children[o];
|
|
255
|
+
p.insertBefore(g, h.nextSibling);
|
|
256
|
+
}), e.textArea.value = e.editorArea.innerHTML);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}, U = {
|
|
261
|
+
name: "accordion",
|
|
262
|
+
init(e) {
|
|
263
|
+
e.addToolbarButton(d.chevronDown, "Insert Accordion", () => {
|
|
264
|
+
e.exec("insertHTML", `
|
|
265
|
+
<details class="play-editor-accordion" open>
|
|
266
|
+
<summary class="play-editor-accordion-title">Click to expand</summary>
|
|
267
|
+
<div class="play-editor-accordion-content">
|
|
268
|
+
<p>Accordion content goes here...</p>
|
|
269
|
+
</div>
|
|
270
|
+
</details>
|
|
271
|
+
<p><br></p>
|
|
272
|
+
`);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}, j = {
|
|
276
|
+
name: "page-break",
|
|
277
|
+
init(e) {
|
|
278
|
+
e.addToolbarDivider(), e.addToolbarButton(d.minus, "Horizontal Rule", () => {
|
|
279
|
+
e.exec("insertHorizontalRule");
|
|
280
|
+
}), e.addToolbarButton(d.fileBreak, "Page Break", () => {
|
|
281
|
+
e.exec("insertHTML", `
|
|
282
|
+
<div class="play-editor-page-break" contenteditable="false">
|
|
283
|
+
<span>Page Break</span>
|
|
284
|
+
</div>
|
|
285
|
+
<p><br></p>
|
|
286
|
+
`);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}, $ = {
|
|
290
|
+
name: "toc",
|
|
291
|
+
init(e) {
|
|
292
|
+
e.addToolbarButton(d.listTree, "Insert Table of Contents", () => {
|
|
293
|
+
const t = e.editorArea.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
|
294
|
+
if (t.length === 0) {
|
|
295
|
+
alert("No headings found to generate a Table of Contents.");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
let a = '<div class="play-editor-toc" contenteditable="false"><h3>Table of Contents</h3><ul>';
|
|
299
|
+
t.forEach((n, o) => {
|
|
300
|
+
const i = `toc-heading-${o}`;
|
|
301
|
+
n.id = i;
|
|
302
|
+
const p = (parseInt(n.tagName.charAt(1)) - 1) * 20;
|
|
303
|
+
a += `<li style="margin-left: ${p}px"><a href="#${i}">${n.textContent}</a></li>`;
|
|
304
|
+
}), a += "</ul></div><p><br></p>", e.exec("insertHTML", a);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}, z = {
|
|
308
|
+
name: "paste-image",
|
|
309
|
+
init(e) {
|
|
310
|
+
e.editorArea.addEventListener("paste", (t) => {
|
|
311
|
+
const a = t.clipboardData?.items;
|
|
312
|
+
if (a)
|
|
313
|
+
for (let n = 0; n < a.length; n++) {
|
|
314
|
+
const o = a[n];
|
|
315
|
+
if (o.type.startsWith("image/")) {
|
|
316
|
+
t.preventDefault();
|
|
317
|
+
const i = o.getAsFile();
|
|
318
|
+
if (!i) return;
|
|
319
|
+
const s = new FileReader();
|
|
320
|
+
s.onload = (p) => {
|
|
321
|
+
const g = p.target?.result;
|
|
322
|
+
if (g) {
|
|
323
|
+
const h = document.createElement("img");
|
|
324
|
+
h.src = g, h.style.maxWidth = "100%", h.style.height = "auto", h.style.borderRadius = "6px", h.style.margin = "0.5em 0";
|
|
325
|
+
const l = window.getSelection();
|
|
326
|
+
if (l && l.rangeCount > 0) {
|
|
327
|
+
const r = l.getRangeAt(0);
|
|
328
|
+
r.deleteContents(), r.insertNode(h), r.setStartAfter(h), r.collapse(!0), l.removeAllRanges(), l.addRange(r);
|
|
329
|
+
} else
|
|
330
|
+
e.editorArea.appendChild(h);
|
|
331
|
+
e.textArea.value = e.editorArea.innerHTML;
|
|
332
|
+
}
|
|
333
|
+
}, s.readAsDataURL(i);
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}, w = [];
|
|
340
|
+
function E(e = {}) {
|
|
341
|
+
const t = e.trigger || "@", a = e.users || w;
|
|
342
|
+
return {
|
|
343
|
+
name: "mentions",
|
|
344
|
+
init(n) {
|
|
345
|
+
n.addToolbarDivider(), n.addToolbarButton(d.atSign, "Mention (@)", () => {
|
|
346
|
+
n.editorArea.focus(), n.exec("insertHTML", t), h();
|
|
347
|
+
});
|
|
348
|
+
let o = null;
|
|
349
|
+
function i() {
|
|
350
|
+
o && (o.remove(), o = null);
|
|
351
|
+
}
|
|
352
|
+
function s() {
|
|
353
|
+
const l = window.getSelection();
|
|
354
|
+
if (!l || l.rangeCount === 0) return null;
|
|
355
|
+
const r = l.getRangeAt(0).cloneRange();
|
|
356
|
+
r.collapse(!1);
|
|
357
|
+
const m = document.createElement("span");
|
|
358
|
+
m.textContent = "โ", r.insertNode(m);
|
|
359
|
+
const u = m.getBoundingClientRect(), x = n.editorArea.getBoundingClientRect(), y = {
|
|
360
|
+
top: u.bottom - x.top + n.editorArea.scrollTop,
|
|
361
|
+
left: u.left - x.left
|
|
362
|
+
};
|
|
363
|
+
return m.remove(), l.getRangeAt(0).commonAncestorContainer.parentElement?.normalize(), y;
|
|
364
|
+
}
|
|
365
|
+
function p(l) {
|
|
366
|
+
const r = window.getSelection();
|
|
367
|
+
if (!r || r.rangeCount === 0) return;
|
|
368
|
+
const m = r.getRangeAt(0), u = m.startContainer;
|
|
369
|
+
if (u.nodeType === Node.TEXT_NODE) {
|
|
370
|
+
const x = u.textContent || "", y = m.startOffset, v = x.lastIndexOf(t, y);
|
|
371
|
+
if (v !== -1) {
|
|
372
|
+
const f = x.substring(0, v), L = x.substring(y);
|
|
373
|
+
u.textContent = f;
|
|
374
|
+
const b = document.createElement("span");
|
|
375
|
+
b.className = "play-editor-mention", b.contentEditable = "false", b.dataset.userId = l.id, b.textContent = `@${l.name}`;
|
|
376
|
+
const A = document.createTextNode("ย " + L), M = u.parentNode;
|
|
377
|
+
M.insertBefore(b, u.nextSibling), M.insertBefore(A, b.nextSibling);
|
|
378
|
+
const T = document.createRange();
|
|
379
|
+
T.setStart(A, 1), T.collapse(!0), r.removeAllRanges(), r.addRange(T);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
i(), n.textArea.value = n.editorArea.innerHTML;
|
|
383
|
+
}
|
|
384
|
+
async function g(l) {
|
|
385
|
+
i();
|
|
386
|
+
let r;
|
|
387
|
+
if (typeof a == "function") {
|
|
388
|
+
const u = a(l);
|
|
389
|
+
r = u instanceof Promise ? await u : u;
|
|
390
|
+
} else
|
|
391
|
+
r = a.filter(
|
|
392
|
+
(u) => u.name.toLowerCase().includes(l.toLowerCase())
|
|
393
|
+
);
|
|
394
|
+
if (r.length === 0) return;
|
|
395
|
+
const m = s();
|
|
396
|
+
m && (o = document.createElement("div"), o.className = "play-editor-mention-dropdown", o.style.top = `${m.top + 4}px`, o.style.left = `${m.left}px`, r.slice(0, 8).forEach((u, x) => {
|
|
397
|
+
const y = document.createElement("div");
|
|
398
|
+
y.className = "play-editor-mention-item", x === 0 && y.classList.add("active");
|
|
399
|
+
const v = u.name.split(" ").map((f) => f[0]).join("").toUpperCase();
|
|
400
|
+
y.innerHTML = `
|
|
401
|
+
<div class="play-editor-mention-avatar">${u.avatar ? `<img src="${u.avatar}" />` : v}</div>
|
|
402
|
+
<span class="play-editor-mention-name">${u.name}</span>
|
|
403
|
+
`, y.addEventListener("mousedown", (f) => {
|
|
404
|
+
f.preventDefault(), p(u);
|
|
405
|
+
}), o.appendChild(y);
|
|
406
|
+
}), n.editorArea.style.position = "relative", n.editorArea.appendChild(o));
|
|
407
|
+
}
|
|
408
|
+
async function h() {
|
|
409
|
+
const l = window.getSelection();
|
|
410
|
+
if (!l || l.rangeCount === 0) {
|
|
411
|
+
i();
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const r = l.getRangeAt(0), m = r.startContainer;
|
|
415
|
+
if (m.nodeType !== Node.TEXT_NODE) {
|
|
416
|
+
i();
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const u = m.textContent || "", x = r.startOffset, y = u.substring(0, x), v = y.lastIndexOf(t);
|
|
420
|
+
if (v === -1) {
|
|
421
|
+
i();
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const f = y.substring(v + t.length);
|
|
425
|
+
if (f.includes(" ") && f.trim().length > 0) {
|
|
426
|
+
i();
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
await g(f);
|
|
430
|
+
}
|
|
431
|
+
n.editorArea.addEventListener("input", h), n.editorArea.addEventListener("keydown", (l) => {
|
|
432
|
+
if (!o) return;
|
|
433
|
+
const r = o.querySelectorAll(".play-editor-mention-item"), m = o.querySelector(".play-editor-mention-item.active");
|
|
434
|
+
let u = Array.from(r).indexOf(m);
|
|
435
|
+
l.key === "ArrowDown" ? (l.preventDefault(), m?.classList.remove("active"), u = (u + 1) % r.length, r[u].classList.add("active")) : l.key === "ArrowUp" ? (l.preventDefault(), m?.classList.remove("active"), u = (u - 1 + r.length) % r.length, r[u].classList.add("active")) : l.key === "Enter" || l.key === "Tab" ? m && (l.preventDefault(), m.dispatchEvent(new MouseEvent("mousedown"))) : l.key === "Escape" && (l.preventDefault(), i());
|
|
436
|
+
}), document.addEventListener("click", (l) => {
|
|
437
|
+
o && !o.contains(l.target) && i();
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const q = E(), _ = {
|
|
443
|
+
name: "code-block",
|
|
444
|
+
init(e) {
|
|
445
|
+
e.addToolbarDivider(), e.addToolbarButton(d.code, "Inline Code", () => {
|
|
446
|
+
const n = window.getSelection();
|
|
447
|
+
if (!n || n.rangeCount === 0) return;
|
|
448
|
+
const o = n.getRangeAt(0), i = o.toString();
|
|
449
|
+
if (i) {
|
|
450
|
+
const s = document.createElement("code");
|
|
451
|
+
s.className = "play-editor-inline-code", s.textContent = i, o.deleteContents(), o.insertNode(s), o.setStartAfter(s), o.collapse(!0), n.removeAllRanges(), n.addRange(o);
|
|
452
|
+
} else {
|
|
453
|
+
const s = document.createElement("code");
|
|
454
|
+
s.className = "play-editor-inline-code", s.innerHTML = " ", o.insertNode(s), o.selectNodeContents(s), n.removeAllRanges(), n.addRange(o);
|
|
455
|
+
}
|
|
456
|
+
e.textArea.value = e.editorArea.innerHTML;
|
|
457
|
+
}), e.addToolbarButton(d.braces, "Code Block", () => {
|
|
458
|
+
const o = window.getSelection()?.toString() || "// your code here", i = `
|
|
459
|
+
<pre class="play-editor-code-block"><code>${R(o)}</code></pre>
|
|
460
|
+
<p><br></p>
|
|
461
|
+
`;
|
|
462
|
+
e.exec("insertHTML", i);
|
|
463
|
+
});
|
|
464
|
+
let t = !1;
|
|
465
|
+
const a = e.addToolbarButton(d.code, "Toggle HTML Source", () => {
|
|
466
|
+
if (t = !t, t) {
|
|
467
|
+
const n = e.editorArea.innerHTML;
|
|
468
|
+
e.editorArea.innerText = n, e.editorArea.classList.add("play-editor-source-view"), a.classList.add("play-editor-btn-active");
|
|
469
|
+
} else {
|
|
470
|
+
const n = e.editorArea.innerText;
|
|
471
|
+
e.editorArea.innerHTML = n, e.editorArea.classList.remove("play-editor-source-view"), a.classList.remove("play-editor-btn-active"), e.textArea.value = e.editorArea.innerHTML;
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
function R(e) {
|
|
477
|
+
const t = document.createElement("div");
|
|
478
|
+
return t.textContent = e, t.innerHTML;
|
|
479
|
+
}
|
|
480
|
+
const F = {
|
|
481
|
+
name: "datetime",
|
|
482
|
+
init(e) {
|
|
483
|
+
e.addToolbarDivider(), e.addToolbarButton(d.calendar, "Insert Date", () => {
|
|
484
|
+
const t = /* @__PURE__ */ new Date(), a = t.toLocaleDateString(void 0, {
|
|
485
|
+
year: "numeric",
|
|
486
|
+
month: "long",
|
|
487
|
+
day: "numeric"
|
|
488
|
+
});
|
|
489
|
+
e.exec("insertHTML", `<time class="play-editor-datetime" datetime="${t.toISOString()}">${a}</time>`);
|
|
490
|
+
}), e.addToolbarButton(d.clock, "Insert Time", () => {
|
|
491
|
+
const t = /* @__PURE__ */ new Date(), a = t.toLocaleTimeString(void 0, {
|
|
492
|
+
hour: "2-digit",
|
|
493
|
+
minute: "2-digit"
|
|
494
|
+
});
|
|
495
|
+
e.exec("insertHTML", `<time class="play-editor-datetime" datetime="${t.toISOString()}">${a}</time>`);
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}, C = {
|
|
499
|
+
Smileys: ["๐", "๐", "๐", "๐", "๐", "๐
", "๐คฃ", "๐", "๐", "๐", "๐", "๐", "๐ฅฐ", "๐", "๐คฉ", "๐", "๐", "๐", "๐", "๐", "๐", "๐คช", "๐", "๐ค", "๐ค", "๐คญ", "๐คซ", "๐ค", "๐ซก"],
|
|
500
|
+
Gestures: ["๐", "๐", "๐", "๐", "๐ค", "๐", "โ๏ธ", "๐ค", "๐ค", "๐ค", "๐", "๐ค", "๐", "โ", "๐๏ธ", "๐", "๐ช", "๐ฆพ"],
|
|
501
|
+
Hearts: ["โค๏ธ", "๐งก", "๐", "๐", "๐", "๐", "๐ค", "๐ค", "๐ค", "๐", "โฃ๏ธ", "๐", "๐", "๐", "๐", "๐", "๐", "๐"],
|
|
502
|
+
Objects: ["๐", "๐", "๐", "๐", "๐", "๐ฅ", "โญ", "๐", "๐ก", "๐ฅ", "โจ", "๐ฏ", "โ
", "โ", "โ ๏ธ", "๐", "๐", "๐", "๐", "๐
", "๐", "๐"],
|
|
503
|
+
Arrows: ["โก๏ธ", "โฌ
๏ธ", "โฌ๏ธ", "โฌ๏ธ", "โ๏ธ", "โ๏ธ", "โ๏ธ", "โ๏ธ", "โ๏ธ", "โ๏ธ", "๐", "๐"]
|
|
504
|
+
}, V = {
|
|
505
|
+
name: "emoji",
|
|
506
|
+
init(e) {
|
|
507
|
+
let t = null;
|
|
508
|
+
e.addToolbarButton(d.smile, "Insert Emoji", () => {
|
|
509
|
+
if (t) {
|
|
510
|
+
t.remove(), t = null;
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const a = window.getSelection();
|
|
514
|
+
let n = null;
|
|
515
|
+
a && a.rangeCount > 0 && (n = a.getRangeAt(0).cloneRange()), t = document.createElement("div"), t.className = "play-editor-emoji-picker";
|
|
516
|
+
const o = document.createElement("div");
|
|
517
|
+
o.className = "play-editor-emoji-tabs";
|
|
518
|
+
const i = document.createElement("div");
|
|
519
|
+
i.className = "play-editor-emoji-grid";
|
|
520
|
+
const s = Object.keys(C);
|
|
521
|
+
function p(h) {
|
|
522
|
+
i.innerHTML = "", C[h].forEach((l) => {
|
|
523
|
+
const r = document.createElement("button");
|
|
524
|
+
r.type = "button", r.className = "play-editor-emoji-item", r.textContent = l, r.addEventListener("mousedown", (m) => {
|
|
525
|
+
m.preventDefault(), e.editorArea.focus(), n && (a?.removeAllRanges(), a?.addRange(n)), e.exec("insertHTML", l), a && a.rangeCount > 0 && (n = a.getRangeAt(0).cloneRange());
|
|
526
|
+
}), i.appendChild(r);
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
s.forEach((h, l) => {
|
|
530
|
+
const r = document.createElement("button");
|
|
531
|
+
r.type = "button", r.className = "play-editor-emoji-tab", l === 0 && r.classList.add("active"), r.textContent = h, r.addEventListener("mousedown", (m) => {
|
|
532
|
+
m.preventDefault(), o.querySelectorAll(".play-editor-emoji-tab").forEach((u) => u.classList.remove("active")), r.classList.add("active"), p(h);
|
|
533
|
+
}), o.appendChild(r);
|
|
534
|
+
}), t.appendChild(o), t.appendChild(i), e.container.style.position = "relative", e.container.appendChild(t), p(s[0]);
|
|
535
|
+
const g = (h) => {
|
|
536
|
+
t && !t.contains(h.target) && (t.remove(), t = null, document.removeEventListener("mousedown", g));
|
|
537
|
+
};
|
|
538
|
+
setTimeout(() => document.addEventListener("mousedown", g), 0);
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
export {
|
|
543
|
+
U as AccordionPlugin,
|
|
544
|
+
P as AlignmentPlugin,
|
|
545
|
+
_ as CodeBlockPlugin,
|
|
546
|
+
N as ColorPlugin,
|
|
547
|
+
F as DateTimePlugin,
|
|
548
|
+
I as DirectionalityPlugin,
|
|
549
|
+
k as Editor,
|
|
550
|
+
V as EmojiPlugin,
|
|
551
|
+
B as FormattingPlugin,
|
|
552
|
+
S as LinksPlugin,
|
|
553
|
+
H as ListsPlugin,
|
|
554
|
+
D as MediaPlugin,
|
|
555
|
+
q as MentionsPlugin,
|
|
556
|
+
j as PageBreakPlugin,
|
|
557
|
+
z as PasteImagePlugin,
|
|
558
|
+
O as TablesPlugin,
|
|
559
|
+
$ as TocPlugin,
|
|
560
|
+
E as createMentionsPlugin
|
|
561
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap";:root{--pe-bg: #ffffff;--pe-text: #1e293b;--pe-text-muted: #64748b;--pe-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--pe-border: #e2e8f0;--pe-radius: 10px;--pe-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px -1px rgba(0, 0, 0, .1);--pe-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1);--pe-focus: rgba(59, 130, 246, .45);--pe-toolbar-bg: #f8fafc;--pe-btn-hover: rgba(0, 0, 0, .06);--pe-btn-active: rgba(0, 0, 0, .1);--pe-accent: #3b82f6}.play-editor-container{border:1px solid var(--pe-border);border-radius:var(--pe-radius);background:var(--pe-bg);font-family:var(--pe-font);color:var(--pe-text);overflow:hidden;display:flex;flex-direction:column;box-shadow:var(--pe-shadow);transition:border-color .2s,box-shadow .2s}.play-editor-container:focus-within{border-color:var(--pe-accent);box-shadow:0 0 0 3px var(--pe-focus)}.play-editor-toolbar{padding:6px 10px;background:var(--pe-toolbar-bg);border-bottom:1px solid var(--pe-border);display:flex;flex-wrap:wrap;gap:2px;align-items:center}.play-editor-btn{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;padding:0;border:none;border-radius:6px;background:transparent;color:var(--pe-text-muted);cursor:pointer;position:relative;transition:background .15s,color .15s,transform .1s}.play-editor-btn svg{width:18px;height:18px;pointer-events:none}.play-editor-btn:hover{background:var(--pe-btn-hover);color:var(--pe-text)}.play-editor-btn:active{background:var(--pe-btn-active);transform:scale(.94)}.play-editor-btn:after{content:attr(title);position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%) scale(.92);padding:4px 8px;border-radius:6px;background:#1e293b;color:#f8fafc;font-size:11px;font-weight:500;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .15s,transform .15s;z-index:10}.play-editor-btn:hover:after{opacity:1;transform:translate(-50%) scale(1)}.play-editor-divider{width:1px;height:22px;background:var(--pe-border);margin:0 4px;flex-shrink:0}.play-editor-content{min-height:300px;padding:1.25rem 1.5rem;outline:none;overflow-y:auto;font-size:15px;line-height:1.7;color:var(--pe-text)}.play-editor-content:empty:before{content:"Start typingโฆ";color:var(--pe-text-muted);pointer-events:none;display:block}.play-editor-content p{margin:0 0 .75em}.play-editor-content h1{font-size:1.75em;font-weight:700;margin:1.2em 0 .4em;color:#0f172a}.play-editor-content h2{font-size:1.35em;font-weight:600;margin:1em 0 .35em;color:#0f172a}.play-editor-content h3{font-size:1.15em;font-weight:600;margin:.8em 0 .3em;color:#0f172a}.play-editor-content a{color:var(--pe-accent);text-decoration:underline}.play-editor-content img{max-width:100%;height:auto;border-radius:6px;margin:.5em 0}.play-editor-content hr{border:none;border-top:2px solid var(--pe-border);margin:1.5em 0}.play-editor-content blockquote{border-left:3px solid var(--pe-accent);padding-left:1em;margin-left:0;color:var(--pe-text-muted)}.play-editor-color-picker{position:relative;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:6px;cursor:pointer;border:none;transition:background .15s;color:var(--pe-text-muted)}.play-editor-color-picker:hover{background:var(--pe-btn-hover);color:var(--pe-text)}.play-editor-color-picker input[type=color]{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer}.play-editor-color-picker span{pointer-events:none;display:flex;align-items:center}.play-editor-color-picker span svg{width:18px;height:18px}.play-editor-table{border-collapse:collapse;width:100%;margin:1em 0}.play-editor-table td,.play-editor-table th{border:1px solid var(--pe-border);padding:10px 14px;min-width:60px;font-size:14px}.play-editor-table th{background:var(--pe-toolbar-bg);font-weight:600}.play-editor-accordion{border:1px solid var(--pe-border);border-radius:8px;margin:1em 0;overflow:hidden}.play-editor-accordion summary{padding:12px 16px;background:var(--pe-toolbar-bg);cursor:pointer;font-weight:600;font-size:14px;-webkit-user-select:none;user-select:none;list-style:none;display:flex;align-items:center;gap:8px}.play-editor-accordion summary:before{content:"โธ";transition:transform .2s}.play-editor-accordion[open] summary:before{transform:rotate(90deg)}.play-editor-accordion-content{padding:14px 16px}.play-editor-page-break{page-break-after:always;display:flex;align-items:center;gap:12px;margin:1.5em 0}.play-editor-page-break:before,.play-editor-page-break:after{content:"";flex:1;border-top:2px dashed var(--pe-border)}.play-editor-page-break span{font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--pe-text-muted);white-space:nowrap}.play-editor-toc{background:var(--pe-toolbar-bg);border:1px solid var(--pe-border);border-radius:8px;padding:16px 20px;margin:1em 0}.play-editor-toc h3{font-size:14px;font-weight:700;margin:0 0 10px;text-transform:uppercase;letter-spacing:.04em;color:var(--pe-text-muted)}.play-editor-toc ul{list-style:none;padding:0;margin:0}.play-editor-toc li{padding:4px 0}.play-editor-toc a{color:var(--pe-accent);text-decoration:none;font-size:14px;font-weight:500}.play-editor-toc a:hover{text-decoration:underline}.play-editor-mention{display:inline-flex;align-items:center;background:linear-gradient(135deg,#eff6ff,#e0e7ff);color:var(--pe-accent);font-weight:600;font-size:.875em;padding:2px 8px;border-radius:12px;margin:0 2px;-webkit-user-select:all;user-select:all;cursor:default;white-space:nowrap}.play-editor-mention-dropdown{position:absolute;z-index:100;min-width:220px;max-height:260px;overflow-y:auto;background:var(--pe-bg);border:1px solid var(--pe-border);border-radius:10px;box-shadow:0 10px 25px -5px #00000026,0 8px 10px -6px #0000001a;padding:4px}.play-editor-mention-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:8px;cursor:pointer;transition:background .12s}.play-editor-mention-item:hover,.play-editor-mention-item.active{background:var(--pe-btn-hover)}.play-editor-mention-avatar{width:30px;height:30px;border-radius:50%;background:linear-gradient(135deg,#3b82f6,#8b5cf6);color:#fff;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.play-editor-mention-avatar img{width:100%;height:100%;border-radius:50%;object-fit:cover}.play-editor-mention-name{font-size:13px;font-weight:500;color:var(--pe-text)}.play-editor-inline-code{background:#f1f5f9;color:#e11d48;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:.875em;padding:2px 6px;border-radius:4px;border:1px solid var(--pe-border)}.play-editor-code-block{background:#1e293b;color:#e2e8f0;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:13px;line-height:1.6;padding:16px 20px;border-radius:8px;overflow-x:auto;margin:1em 0;tab-size:2}.play-editor-code-block code{background:transparent;color:inherit;padding:0;border:none;font-size:inherit}.play-editor-source-view{font-family:SF Mono,Fira Code,Cascadia Code,monospace!important;font-size:13px!important;white-space:pre-wrap;background:#1e293b!important;color:#e2e8f0!important}.play-editor-btn-active{background:var(--pe-accent)!important;color:#fff!important}.play-editor-datetime{display:inline-flex;align-items:center;background:#f0fdf4;color:#16a34a;font-weight:500;font-size:.875em;padding:2px 8px;border-radius:4px;border:1px solid #bbf7d0;white-space:nowrap}.play-editor-emoji-picker{position:absolute;top:0;left:0;z-index:200;width:340px;background:var(--pe-bg);border:1px solid var(--pe-border);border-radius:12px;box-shadow:0 20px 25px -5px #00000026,0 8px 10px -6px #0000001a;padding:8px;animation:pe-fade-in .15s ease}@keyframes pe-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.play-editor-emoji-tabs{display:flex;gap:2px;padding-bottom:6px;border-bottom:1px solid var(--pe-border);margin-bottom:6px;overflow-x:auto}.play-editor-emoji-tab{background:transparent;border:none;padding:4px 10px;border-radius:6px;font-size:11px;font-weight:600;font-family:inherit;color:var(--pe-text-muted);cursor:pointer;white-space:nowrap;transition:background .12s,color .12s}.play-editor-emoji-tab:hover{background:var(--pe-btn-hover)}.play-editor-emoji-tab.active{background:var(--pe-accent);color:#fff}.play-editor-emoji-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px;max-height:200px;overflow-y:auto;padding:2px}.play-editor-emoji-item{width:36px;height:36px;display:flex;align-items:center;justify-content:center;font-size:20px;border:none;background:transparent;border-radius:6px;cursor:pointer;transition:background .1s,transform .1s}.play-editor-emoji-item:hover{background:var(--pe-btn-hover);transform:scale(1.15)}
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),i=require("react"),e=require("./index.cjs"),P=[e.FormattingPlugin,e.ListsPlugin,e.ColorPlugin,e.DirectionalityPlugin,e.AlignmentPlugin,e.LinksPlugin,e.MediaPlugin,e.TablesPlugin,e.AccordionPlugin,e.PageBreakPlugin,e.TocPlugin,e.PasteImagePlugin,e.MentionsPlugin,e.CodeBlockPlugin,e.DateTimePlugin,e.EmojiPlugin],s=i.forwardRef(({defaultValue:a="",onChange:u,plugins:c,className:g,minHeight:o},d)=>{const r=i.useRef(null),n=i.useRef(null);return i.useImperativeHandle(d,()=>({getContent:()=>n.current?.getContent()??"",setContent:t=>n.current?.setContent(t),editor:n.current})),i.useEffect(()=>{if(!r.current||n.current)return;const t=new e.Editor(r.current,c??P);n.current=t,o&&(t.editorArea.style.minHeight=`${o}px`),u&&t.editorArea.addEventListener("input",()=>{u(t.getContent())})},[]),l.jsx("div",{className:g,children:l.jsx("textarea",{ref:r,defaultValue:a,style:{display:"none"}})})});s.displayName="PlayEditor";exports.PlayEditor=s;
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ForwardRefExoticComponent } from 'react';
|
|
2
|
+
import { RefAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
declare class Editor {
|
|
5
|
+
container: HTMLElement;
|
|
6
|
+
textArea: HTMLTextAreaElement;
|
|
7
|
+
editorArea: HTMLDivElement;
|
|
8
|
+
toolbar: HTMLDivElement;
|
|
9
|
+
private plugins;
|
|
10
|
+
constructor(selector: string | HTMLTextAreaElement, plugins?: Plugin_2[]);
|
|
11
|
+
private init;
|
|
12
|
+
exec(command: string, value?: string | undefined): void;
|
|
13
|
+
addToolbarButton(iconHtml: string, tooltip: string, onClick: () => void): HTMLButtonElement;
|
|
14
|
+
addToolbarDivider(): void;
|
|
15
|
+
getContent(): string;
|
|
16
|
+
setContent(html: string): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export declare const PlayEditor: ForwardRefExoticComponent<PlayEditorProps & RefAttributes<PlayEditorRef>>;
|
|
20
|
+
|
|
21
|
+
export declare interface PlayEditorProps {
|
|
22
|
+
/** Initial HTML content */
|
|
23
|
+
defaultValue?: string;
|
|
24
|
+
/** Called whenever the editor content changes */
|
|
25
|
+
onChange?: (html: string) => void;
|
|
26
|
+
/** Custom plugins array. If not provided, all built-in plugins are loaded. */
|
|
27
|
+
plugins?: Plugin_2[];
|
|
28
|
+
/** Additional CSS class for the container wrapper */
|
|
29
|
+
className?: string;
|
|
30
|
+
/** Minimum height of the editor content area in px */
|
|
31
|
+
minHeight?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export declare interface PlayEditorRef {
|
|
35
|
+
/** Get the current HTML content */
|
|
36
|
+
getContent: () => string;
|
|
37
|
+
/** Set the HTML content programmatically */
|
|
38
|
+
setContent: (html: string) => void;
|
|
39
|
+
/** Access the underlying Editor instance */
|
|
40
|
+
editor: Editor | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
declare interface Plugin_2 {
|
|
44
|
+
name: string;
|
|
45
|
+
init(editor: Editor): void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { }
|
package/dist/react.mjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as P, useRef as l, useImperativeHandle as c, useEffect as d } from "react";
|
|
3
|
+
import { Editor as f, FormattingPlugin as m, ListsPlugin as p, ColorPlugin as y, DirectionalityPlugin as C, AlignmentPlugin as E, LinksPlugin as L, MediaPlugin as x, TablesPlugin as A, AccordionPlugin as R, PageBreakPlugin as k, TocPlugin as v, PasteImagePlugin as I, MentionsPlugin as T, CodeBlockPlugin as j, DateTimePlugin as w, EmojiPlugin as B } from "./index.mjs";
|
|
4
|
+
const D = [
|
|
5
|
+
m,
|
|
6
|
+
p,
|
|
7
|
+
y,
|
|
8
|
+
C,
|
|
9
|
+
E,
|
|
10
|
+
L,
|
|
11
|
+
x,
|
|
12
|
+
A,
|
|
13
|
+
R,
|
|
14
|
+
k,
|
|
15
|
+
v,
|
|
16
|
+
I,
|
|
17
|
+
T,
|
|
18
|
+
j,
|
|
19
|
+
w,
|
|
20
|
+
B
|
|
21
|
+
], M = P(
|
|
22
|
+
({ defaultValue: u = "", onChange: i, plugins: a, className: g, minHeight: r }, s) => {
|
|
23
|
+
const n = l(null), t = l(null);
|
|
24
|
+
return c(s, () => ({
|
|
25
|
+
getContent: () => t.current?.getContent() ?? "",
|
|
26
|
+
setContent: (e) => t.current?.setContent(e),
|
|
27
|
+
editor: t.current
|
|
28
|
+
})), d(() => {
|
|
29
|
+
if (!n.current || t.current) return;
|
|
30
|
+
const e = new f(
|
|
31
|
+
n.current,
|
|
32
|
+
a ?? D
|
|
33
|
+
);
|
|
34
|
+
t.current = e, r && (e.editorArea.style.minHeight = `${r}px`), i && e.editorArea.addEventListener("input", () => {
|
|
35
|
+
i(e.getContent());
|
|
36
|
+
});
|
|
37
|
+
}, []), /* @__PURE__ */ o("div", { className: g, children: /* @__PURE__ */ o(
|
|
38
|
+
"textarea",
|
|
39
|
+
{
|
|
40
|
+
ref: n,
|
|
41
|
+
defaultValue: u,
|
|
42
|
+
style: { display: "none" }
|
|
43
|
+
}
|
|
44
|
+
) });
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
M.displayName = "PlayEditor";
|
|
48
|
+
export {
|
|
49
|
+
M as PlayEditor
|
|
50
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "plug-and-play-editor",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./react": {
|
|
16
|
+
"types": "./dist/react.d.ts",
|
|
17
|
+
"import": "./dist/react.mjs",
|
|
18
|
+
"require": "./dist/react.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./style.css": "./dist/style.css"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"dev": "vite",
|
|
27
|
+
"build": "tsc && vite build",
|
|
28
|
+
"preview": "vite preview"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": ">=17.0.0",
|
|
32
|
+
"react-dom": ">=17.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"react": {
|
|
36
|
+
"optional": true
|
|
37
|
+
},
|
|
38
|
+
"react-dom": {
|
|
39
|
+
"optional": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^25.3.2",
|
|
44
|
+
"@types/react": "^19.1.6",
|
|
45
|
+
"@types/react-dom": "^19.1.6",
|
|
46
|
+
"typescript": "~5.9.3",
|
|
47
|
+
"vite": "^7.3.1",
|
|
48
|
+
"vite-plugin-dts": "^4.5.4"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"lucide": "^0.575.0"
|
|
52
|
+
}
|
|
53
|
+
}
|