@editora/core
Advanced tools
| .rte-table,table{border-collapse:collapse;width:100%;margin:1rem 0;border:1px solid #ddd;font-size:14px;line-height:1.4;position:relative}.rte-table td,.rte-table th,table td,table th{border:1px solid #ddd;padding:8px 12px;min-width:80px;vertical-align:top;position:relative;user-select:none}.rte-table td:focus,.rte-table th:focus,table td:focus,table th:focus{outline:2px solid #007acc;outline-offset:-2px}.rte-table th,table th{background-color:#f8f9fa;font-weight:600;text-align:left}.rte-table td p,table td p{margin:0;padding:0}.rte-table td p:empty:before,table td p:empty:before{content:"";display:inline-block}.rte-table td[contenteditable]:empty:before,table td[contenteditable]:empty:before{content:"Type here...";color:#999;font-style:italic;pointer-events:none}.rte-table tr:hover,table tr:hover{background-color:#f8f9fa}.rte-table td.selected,table td.selected{background-color:#e3f2fd;border-color:#2196f3}.table-toolbar{background:#fff;border:1px solid #d0d0d0;border-radius:4px;box-shadow:0 2px 8px #0000001a;padding:4px;display:flex;align-items:center;gap:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;min-width:max-content}.toolbar-section{display:flex;align-items:center;gap:2px}.toolbar-divider{width:1px;height:20px;background:#e0e0e0;margin:0 4px}.toolbar-icon-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid transparent;background:transparent;cursor:pointer;color:#333;border-radius:3px;transition:all .2s ease;flex-shrink:0;font-size:14px;line-height:1}.toolbar-icon-btn svg{width:16px;height:16px}.toolbar-icon-btn:hover:not(:disabled){background:#f0f0f0;border-color:#d0d0d0;color:#06c}.toolbar-icon-btn:active:not(:disabled){background:#e8f0ff;border-color:#06c;transform:scale(.95)}.toolbar-icon-btn:disabled{opacity:.4;cursor:not-allowed;color:#ccc}.toolbar-icon-btn-danger{color:#d32f2f}.toolbar-icon-btn-danger:hover:not(:disabled){background:#fff3f3;border-color:#fcc;color:#d32f2f}.toolbar-icon-btn-danger:active:not(:disabled){background:#ffebee}.toolbar-icon-btn-delete{color:#d32f2f}.toolbar-icon-btn-delete:hover:not(:disabled){background:#fff3f3;border-color:#fcc;color:#d32f2f}.toolbar-icon-btn-delete:active:not(:disabled){background:#ffebee}.resize-handle{opacity:0;transition:all .15s ease}.resize-handle:hover{opacity:1}td:hover>.resize-handle,th:hover>.resize-handle{opacity:1}.table-resize-handle{position:absolute;bottom:-4px;right:-4px;width:12px;height:12px;background:transparent;cursor:nwse-resize;z-index:10;transition:background .15s ease}.table-resize-handle:after{content:"";position:absolute;bottom:0;right:0;width:8px;height:8px;background:#0066cc4d;border-bottom:2px solid #0066cc;border-right:2px solid #0066cc;border-radius:0 0 2px;opacity:0;transition:opacity .15s ease}.table-resize-handle:hover:after{opacity:1}.rte-table:hover .table-resize-handle:after,table:hover .table-resize-handle:after{opacity:1}@media(max-width:768px){.rte-table,table{font-size:12px}.rte-table td,.rte-table th,table td,table th{padding:4px 6px;min-width:60px}.table-toolbar{padding:3px;gap:0;max-width:90vw;overflow-x:auto}.toolbar-icon-btn{width:26px;height:26px}.toolbar-divider{height:18px}}@media print{.rte-table,table{border:1px solid #000}.rte-table td,.rte-table th,table td,table th{border:1px solid #000;padding:4px}.table-toolbar{display:none}} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| "use strict";class g{constructor(t,e,o){this.doc=t,this.selection=e,this.schema=o}static create(t,e){const o=e||t.node("doc",{},[t.node("paragraph")]);return new g(o,{anchor:0,head:0},t)}apply(t,e){return new g(t,e||this.selection,this.schema)}}class E{constructor(t,e){this.nodes=new Map(Object.entries(t)),this.marks=new Map(Object.entries(e))}node(t,e,o){return{type:t,attrs:e,content:o}}text(t,e){return{type:"text",text:t,marks:e}}}class x{constructor(){this.plugins=[],this.pluginConfigs=new Map}register(t,e){if(this.plugins.push(t),e&&this.pluginConfigs.set(t.name,e),t.initialize){const o=this.pluginConfigs.get(t.name)||t.config;t.initialize(o)}}unregister(t){const e=this.plugins.findIndex(o=>o.name===t);if(e>-1){const o=this.plugins[e];o.destroy&&o.destroy(),this.plugins.splice(e,1),this.pluginConfigs.delete(t)}}getPlugin(t){return this.plugins.find(e=>e.name===t)}getPluginConfig(t){return this.pluginConfigs.get(t)}buildSchema(){const t={},e={};return this.plugins.forEach(o=>{o.nodes&&Object.assign(t,o.nodes),o.marks&&Object.assign(e,o.marks)}),new E(t,e)}getCommands(){const t={};return this.plugins.forEach(e=>{e.commands&&Object.assign(t,e.commands)}),t}getToolbarItems(){return this.plugins.flatMap(t=>t.toolbar||[])}async executePluginCommand(t,e,...o){const i=this.getPlugin(t);if(!i)throw new Error(`Plugin not found: ${t}`);const n=this.getPluginConfig(t)||i.config||{},s=n.mode||"local";try{switch(s){case"local":return i.executeLocal?i.executeLocal(e,...o):null;case"api":if(!i.executeAPI)throw new Error(`Plugin ${t} does not support API mode`);return await i.executeAPI(e,...o);case"hybrid":if(i.executeHybrid)return await i.executeHybrid(e,...o);try{if(i.executeAPI)return await i.executeAPI(e,...o)}catch(r){if(console.warn(`API execution failed for ${t}, falling back to local`,r),i.executeLocal&&n.fallbackToLocal!==!1)return i.executeLocal(e,...o);throw r}break;default:throw new Error(`Unknown plugin mode: ${s}`)}}catch(r){throw console.error(`Error executing command ${e} on plugin ${t}:`,r),r}}async destroyAll(){const t=this.plugins.filter(e=>e.destroy).map(e=>e.destroy());await Promise.all(t),this.plugins=[],this.pluginConfigs.clear()}}class C{constructor(t={}){this.commands=new Map,Object.entries(t).forEach(([e,o])=>{this.register(e,o)})}register(t,e){this.commands.has(t)&&console.warn(`Command ${t} is being overwritten`),this.commands.set(t,e)}unregister(t){this.commands.delete(t)}get(t){return this.commands.get(t)}has(t){return this.commands.has(t)}getCommandNames(){return Array.from(this.commands.keys())}clear(){this.commands.clear()}}class w{constructor(t={}){this.listeners=new Map,this.isReadonly=!1,this.isDestroyed=!1,this.isReadonly=t.readonly||!1,this.pluginManager=new x,t.plugins&&Array.isArray(t.plugins)&&t.plugins.forEach(o=>this.pluginManager.register(o));const e=this.pluginManager.buildSchema();this.state=g.create(e),this.commandRegistry=new C(this.pluginManager.getCommands())}execCommand(t,e){if(this.isReadonly)return console.warn("Cannot execute commands in readonly mode"),!1;if(this.isDestroyed)return console.warn("Cannot execute commands on destroyed editor"),!1;const o=this.commandRegistry.get(t);if(!o)return console.warn(`Command not found: ${t}`),!1;let i;return e!==void 0?i=o(this.state,e):i=o(this.state),i?(this.setState(i),this.emit("change",this.state),!0):!1}setState(t){this.isDestroyed||(this.state=t,this.emit("stateChange",t))}getState(){return this.state}setReadonly(t){this.isReadonly=t,this.emit("readonlyChange",t)}isReadOnly(){return this.isReadonly}on(t,e){return this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(e),()=>{const o=this.listeners.get(t);if(o){const i=o.indexOf(e);i>-1&&o.splice(i,1)}}}emit(t,...e){const o=this.listeners.get(t);o&&o.forEach(i=>{try{i(...e)}catch(n){console.error(`Error in ${t} handler:`,n)}})}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.listeners.clear(),this.emit("destroy"))}isEditorDestroyed(){return this.isDestroyed}}class k{constructor(t,e,o){this.config=t,this.plugins=e,this.pluginLoader=o}setCommandHandler(t){this.commandHandler=t}parseToolbarString(t){const e=[],o=t.split("|").map(r=>r.trim()),i=this.getAvailableToolbarItems(),n=new Map;i.forEach(r=>{r.command&&n.set(r.command,r),r.type==="group"&&r.label&&n.set(r.label,r)});const s={bold:"toggleBold",italic:"toggleItalic",underline:"toggleUnderline",strikethrough:"toggleStrikethrough",bullist:"toggleBulletList",numlist:"toggleOrderedList",checklist:"toggleChecklist",link:"openLinkDialog",image:"openImageDialog",table:"insertTable",anchor:"insertAnchor",code:"toggleSourceView",blockquote:"toggleBlockquote",undo:"undo",redo:"redo",textColor:"openTextColorPicker",backgroundColor:"openBackgroundColorPicker",fontSize:"fontSize",fontFamily:"setFontFamily",lineHeight:"setLineHeight",heading:"setBlockType",paragraph:"setParagraph",textAlignment:"setTextAlignment",direction:"setDirectionLTR",indent:"increaseIndent",outdent:"decreaseIndent",capitalization:"setCapitalization",math:"insertMath",specialCharacters:"insertSpecialCharacter",emojis:"openEmojiDialog",embedIframe:"openEmbedIframeDialog",fullscreen:"toggleFullscreen",preview:"togglePreview",print:"print",a11yChecker:"toggleA11yChecker",spellCheck:"toggleSpellCheck",comments:"addComment",showHideComments:"toggleComments",toggleComments:"toggleComments",footnote:"insertFootnote",mergeTags:"insertMergeTag",pageBreak:"insertPageBreak",template:"insertTemplate",importWord:"importWord",exportWord:"exportWord",exportPdf:"exportPdf",insertImage:"insertImage",insertVideo:"insertVideo",codeBlock:"insertCodeBlock"};return o.forEach(r=>{const d=[];r.split(/\s+/).filter(Boolean).forEach(p=>{if(p==="direction"){const l=n.get("setDirectionLTR"),u=n.get("setDirectionRTL");l&&d.push({id:"directionLTR",label:l.label,command:l.command,icon:l.icon,type:l.type||"button",options:l.options}),u&&d.push({id:"directionRTL",label:u.label,command:u.command,icon:u.icon,type:u.type||"button",options:u.options});return}if(p==="comments"){const l=n.get("addComment"),u=n.get("toggleComments");l&&d.push({id:"addComment",label:l.label,command:l.command,icon:l.icon,type:l.type||"button",options:l.options}),u&&d.push({id:"toggleComments",label:u.label,command:u.command,icon:u.icon,type:u.type||"button",options:u.options});return}const c=s[p]||p;let a=n.get(c);a||(a=n.get(p)),a&&d.push({id:p,label:a.label,command:a.command,icon:a.icon,type:a.type==="separator"?"separator":a.type||"button",options:a.options,items:a.items})}),d.length>0&&e.push(d)}),e}getAvailableToolbarItems(){let t=this.plugins;return this.pluginLoader&&(t=this.pluginLoader.getRegisteredPluginNames().map(n=>this.pluginLoader.load(n)).filter(n=>n!==null)),t.flatMap(o=>o.toolbar||[])}render(t){this.container=t,t.innerHTML="",t.className="editora-toolbar",this.config.sticky&&t.classList.add("editora-toolbar-sticky"),this.config.position&&t.classList.add(`editora-toolbar-${this.config.position}`);const e=this.config.items||this.getDefaultToolbarString(),o=this.parseToolbarString(e);o.forEach((i,n)=>{const s=document.createElement("div");if(s.className="editora-toolbar-group",i.forEach(r=>{this.appendToolbarButton(s,r)}),t.appendChild(s),n<o.length-1){const r=document.createElement("div");r.className="editora-toolbar-separator",t.appendChild(r)}})}appendToolbarButton(t,e){if(e.type==="separator"){const o=document.createElement("div");o.className="editora-toolbar-separator",t.appendChild(o)}else if(e.type==="dropdown"){const o=this.createDropdown(e);t.appendChild(o)}else if(e.type==="inline-menu"){const o=this.createInlineMenu(e);t.appendChild(o)}else if(e.type==="group"&&e.items&&e.items.length){const o=this.createGroupButton(e);t.appendChild(o)}else if(e.type==="input"){const o=this.createInput(e);t.appendChild(o)}else{const o=this.createButton(e);t.appendChild(o)}}createGroupButton(t){const e=document.createElement("div");if(e.className="editora-toolbar-group-button",e.title=t.label,t.icon)if(t.icon.startsWith("<svg")&&t.icon.endsWith("</svg>")){const o=document.createElement("span");o.className="editora-toolbar-icon",o.innerHTML=t.icon,e.appendChild(o)}else e.innerHTML=t.icon;if(t.items&&t.items.length){const o=document.createElement("div");o.className="editora-toolbar-group-items",t.items.forEach(i=>{this.appendToolbarButton(o,i)}),e.appendChild(o)}return e}createInput(t){const e=document.createElement("input");return e.className=`editora-toolbar-input ${t.label.toLowerCase().replace(/\s+/g,"-")}`,e.type="text",e.title=t.label,e.placeholder=t.placeholder||"",e.setAttribute("data-command",t.command),t.active&&e.classList.add("active"),t.disabled&&(e.disabled=!0),e.addEventListener("click",o=>{o.preventDefault(),this.commandHandler&&this.commandHandler(t.command)}),e}createButton(t){const e=document.createElement("button");if(e.className="editora-toolbar-button",e.type="button",e.title=t.label,e.setAttribute("data-command",t.command),t.icon)if(t.icon.startsWith("<svg")&&t.icon.endsWith("</svg>")){const o=document.createElement("span");o.className="editora-toolbar-icon",o.innerHTML=t.icon,e.appendChild(o)}else e.innerHTML=t.icon;else e.textContent=t.label;return t.active&&e.classList.add("active"),t.disabled&&(e.disabled=!0),e.addEventListener("click",o=>{o.preventDefault(),this.commandHandler&&this.commandHandler(t.command)}),e}createDropdown(t){const e=document.createElement("div");e.className="editora-toolbar-dropdown";const o=document.createElement("button");o.className="editora-toolbar-button editora-toolbar-dropdown-trigger",o.type="button",o.textContent=t.label;const i=document.createElement("div");i.className="editora-toolbar-dropdown-menu",i.style.display="none",t.options&&t.options.forEach(s=>{const r=document.createElement("button");r.className="editora-toolbar-dropdown-item",r.type="button",r.textContent=s.label,r.setAttribute("data-value",s.value),r.addEventListener("click",d=>{d.preventDefault(),this.commandHandler&&this.commandHandler(t.command,s.value),i.style.display="none"}),i.appendChild(r)}),o.addEventListener("click",s=>{s.preventDefault(),s.stopPropagation();const r=i.style.display==="block";i.style.display=r?"none":"block"});const n=s=>{e.contains(s.target)||(i.style.display="none")};return document.addEventListener("click",n),e._cleanupDropdown=()=>{document.removeEventListener("click",n)},e.appendChild(o),e.appendChild(i),e}createInlineMenu(t){const e=document.createElement("div");e.className="editora-toolbar-dropdown editora-toolbar-inline-menu";const o=document.createElement("button");if(o.className="editora-toolbar-button",o.type="button",o.title=t.label,t.icon)if(t.icon.startsWith("<svg")&&t.icon.endsWith("</svg>")){const n=document.createElement("span");n.className="editora-toolbar-icon",n.innerHTML=t.icon,o.appendChild(n)}else o.innerHTML=t.icon;else o.textContent=t.label;const i=document.createElement("div");return i.className="editora-toolbar-dropdown-menu",i.style.display="none",t.options&&t.options.forEach(n=>{const s=document.createElement("button");s.className="editora-toolbar-dropdown-item",s.type="button",s.textContent=n.label,s.setAttribute("data-value",n.value),s.addEventListener("click",r=>{r.preventDefault(),r.stopPropagation(),this.commandHandler&&this.commandHandler(t.command,n.value),i.style.display="none"}),i.appendChild(s)}),o.addEventListener("click",n=>{var r;n.preventDefault(),n.stopPropagation();const s=(r=this.container)==null?void 0:r.querySelectorAll(".editora-toolbar-dropdown-menu");s==null||s.forEach(d=>{d!==i&&(d.style.display="none")}),i.style.display=i.style.display==="none"?"block":"none"}),document.addEventListener("click",n=>{e.contains(n.target)||(i.style.display="none")}),e.appendChild(o),e.appendChild(i),e}getDefaultToolbarString(){return this.getAvailableToolbarItems().map(e=>e.command).join(" ")}updateButtonState(t,e){if(!this.container)return;const o=this.container.querySelector(`[data-command="${t}"]`);o&&(e.active!==void 0&&o.classList.toggle("active",e.active),e.disabled!==void 0&&(o.disabled=e.disabled))}destroy(){this.container&&(this.container.querySelectorAll(".editora-toolbar-dropdown").forEach(e=>{const o=e._cleanupDropdown;o&&o()}),this.container.innerHTML=""),this.commandHandler=void 0}}class v{constructor(t){this.visible=!1,this.config=t}create(t){const e=document.createElement("div");return e.className="editora-floating-toolbar",e.style.display="none",e.style.position="absolute",e.style.zIndex="1000",this.container=e,t.appendChild(e),e}show(t,e){this.container&&(this.container.style.display="block",this.container.style.left=`${t}px`,this.container.style.top=`${e}px`,this.visible=!0)}hide(){this.container&&(this.container.style.display="none",this.visible=!1)}updatePosition(t,e){!this.container||!this.visible||(this.container.style.left=`${t}px`,this.container.style.top=`${e}px`)}isVisible(){return this.visible}destroy(){this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container),this.container=void 0,this.visible=!1}}class L{constructor(t={}){this.statusInfo={},this.config=t}create(t){const e=document.createElement("div");return e.className="editora-statusbar",this.config.position&&e.classList.add(`editora-statusbar-${this.config.position}`),this.container=e,t.appendChild(e),e}update(t){this.statusInfo={...this.statusInfo,...t},this.render()}render(){if(!this.container)return;this.container.innerHTML="";const t=[];this.statusInfo.wordCount!==void 0&&t.push(`Words: ${this.statusInfo.wordCount}`),this.statusInfo.charCount!==void 0&&t.push(`Characters: ${this.statusInfo.charCount}`),this.statusInfo.lineCount!==void 0&&t.push(`Lines: ${this.statusInfo.lineCount}`),this.statusInfo.language&&t.push(`Language: ${this.statusInfo.language}`),this.statusInfo.custom&&Object.entries(this.statusInfo.custom).forEach(([e,o])=>{t.push(`${e}: ${o}`)}),t.forEach((e,o)=>{const i=document.createElement("span");if(i.className="editora-statusbar-item",i.textContent=e,this.container.appendChild(i),o<t.length-1){const n=document.createElement("span");n.className="editora-statusbar-separator",n.textContent="|",this.container.appendChild(n)}})}destroy(){this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container),this.container=void 0}}const y=class y{static resolve(t){const e={};if(Object.assign(e,this.EDITOR_DEFAULTS),t.pluginDefaults&&Object.assign(e,t.pluginDefaults),t.attributes){const o=this.parseAttributes(t.attributes);Object.assign(e,o)}return t.jsConfig&&Object.assign(e,t.jsConfig),e}static parseAttributes(t){const e={};for(const[o,i]of Object.entries(t)){const n=this.kebabToCamel(o);e[n]=this.parseAttributeValue(i)}return e}static parseAttributeValue(t){if(t==="true")return!0;if(t==="false")return!1;if(/^\d+$/.test(t))return parseInt(t,10);if(/^\d+\.\d+$/.test(t))return parseFloat(t);if(t.startsWith("{")||t.startsWith("["))try{return JSON.parse(t)}catch(e){return t}return t}static kebabToCamel(t){return t.replace(/-([a-z])/g,(e,o)=>o.toUpperCase())}static validate(t){const e=[];return t.height!==void 0&&typeof t.height=="number"&&t.height<0&&e.push("height must be a positive number"),t.width!==void 0&&typeof t.width=="number"&&t.width<0&&e.push("width must be a positive number"),t.plugins!==void 0&&!Array.isArray(t.plugins)&&typeof t.plugins!="string"&&e.push("plugins must be an array or string"),t.theme!==void 0&&typeof t.theme!="string"&&e.push("theme must be a string"),{valid:e.length===0,errors:e}}static getDefaults(){return{...this.EDITOR_DEFAULTS}}static merge(...t){const e={};for(const o of t)for(const[i,n]of Object.entries(o))n!=null&&(typeof n=="object"&&!Array.isArray(n)&&e[i]?e[i]=this.merge(e[i],n):e[i]=n);return e}};y.EDITOR_DEFAULTS={height:400,width:"100%",readonly:!1,disabled:!1,menubar:!0,toolbar:!0,plugins:[],theme:"light",content:"",placeholder:"Start typing...",autofocus:!1,autosave:!1,spellcheck:!1,language:"en"};let f=y;class T{constructor(){this.loadedPlugins=new Map,this.pluginRegistry=new Map}register(t,e){this.pluginRegistry.set(t,e)}load(t,e){if(this.loadedPlugins.has(t))return this.loadedPlugins.get(t);const o=this.pluginRegistry.get(t);if(!o)return console.warn(`Plugin not found: ${t}`),null;const i=o();return e&&this.applyPluginConfig(i,e),this.loadedPlugins.set(t,i),i}loadMultiple(t,e){return t.map(o=>this.load(o,e)).filter(o=>o!==null)}parsePluginString(t,e){const o=t.split(/\s+/).filter(Boolean);return this.loadMultiple(o,e)}applyPluginConfig(t,e){t.__pluginConfig=e}unload(t){this.loadedPlugins.delete(t)}clear(){this.loadedPlugins.clear()}getLoadedPluginNames(){return Array.from(this.loadedPlugins.keys())}getRegisteredPluginNames(){return Array.from(this.pluginRegistry.keys())}isLoaded(t){return this.loadedPlugins.has(t)}}const A='.editora-editor{display:flex;flex-direction:column;border:1px solid #ddd;border-radius:4px;background:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;overflow:hidden}.editora-editor *{box-sizing:border-box}.editora-theme-light{background:#fff;color:#333}.editora-theme-dark{background:#1e1e1e;color:#d4d4d4;border-color:#3c3c3c}.editora-toolbar{display:flex;align-items:center;gap:4px;padding:8px;background:#f5f5f5;border-bottom:1px solid #ddd;flex-wrap:wrap}.editora-theme-dark .editora-toolbar{background:#252526;border-bottom-color:#3c3c3c}.editora-toolbar-sticky{position:sticky;top:0;z-index:100}.editora-toolbar-group{display:flex;align-items:center;gap:2px}.editora-toolbar-button{padding:6px 12px;border:1px solid #ccc;background:#fff;cursor:pointer;border-radius:3px;font-weight:600;font-size:14px;height:30px;display:flex;align-items:center;white-space:nowrap}.editora-toolbar-input.font-size{width:40px;padding:.25rem;text-align:center;font-size:14px;background:#fff;border:1px solid var(--rte-color-border-light);border-radius:var(--rte-radius-sm)}.editora-toolbar-group-items{display:flex;align-items:center;border:1px solid #ccc;.editora-toolbar-button{border:none;border-radius:0;&:first-child{border-right:1px solid #ccc;border-top-left-radius:3px;border-bottom-left-radius:3px}&:last-child{border-left:1px solid #ccc;border-top-right-radius:3px;border-bottom-right-radius:3px}}}.editora-theme-dark .editora-toolbar-button{color:#d4d4d4}.editora-toolbar-button:hover{background:#e0e0e0;border-color:#ccc}.editora-theme-dark .editora-toolbar-button:hover{background:#37373d;border-color:#555}.editora-toolbar-button:active,.editora-toolbar-button.active{background:#d0d0d0;border-color:#999}.editora-theme-dark .editora-toolbar-button:active,.editora-theme-dark .editora-toolbar-button.active{background:#2a2d2e;border-color:#666}.editora-toolbar-button:disabled{opacity:.5;cursor:not-allowed}.editora-toolbar-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;line-height:1}.editora-toolbar-button svg,.editora-toolbar-icon svg{width:24px;height:24px;display:block}.editora-toolbar-separator{width:1px;height:24px;background:#ddd;margin:0 4px}.editora-theme-dark .editora-toolbar-separator{background:#3c3c3c}.editora-toolbar-dropdown{position:relative}.editora-toolbar-dropdown-menu{position:absolute;top:100%;left:0;min-width:150px;margin-top:4px;padding:4px 0;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-toolbar-dropdown-menu{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-toolbar-dropdown-item{display:block;width:100%;padding:8px 12px;border:none;background:transparent;color:#333;text-align:left;cursor:pointer;font-size:13px;transition:background .15s ease}.editora-theme-dark .editora-toolbar-dropdown-item{color:#d4d4d4}.editora-toolbar-dropdown-item:hover{background:#f5f5f5}.editora-theme-dark .editora-toolbar-dropdown-item:hover{background:#37373d}.editora-content{flex:1;min-height:200px;padding:16px;outline:none;overflow-y:auto;line-height:1.6}.editora-content:empty:before{content:attr(data-placeholder);color:#999;pointer-events:none}.editora-theme-dark .editora-content:empty:before{color:#6a6a6a}.editora-content h1{font-size:2em;margin:.67em 0;font-weight:600}.editora-content h2{font-size:1.5em;margin:.75em 0;font-weight:600}.editora-content h3{font-size:1.17em;margin:.83em 0;font-weight:600}.editora-content p{margin:1em 0}.editora-content ul,.editora-content ol{margin:1em 0;padding-left:2em}.editora-content a{color:#06c;text-decoration:underline}.editora-theme-dark .editora-content a{color:#4db8ff}.editora-content code{padding:2px 4px;background:#f5f5f5;border-radius:3px;font-family:Monaco,Menlo,Consolas,monospace;font-size:.9em}.editora-theme-dark .editora-content code{background:#1e1e1e}.editora-content pre{padding:12px;background:#f5f5f5;border-radius:4px;overflow-x:auto;margin:1em 0}.editora-theme-dark .editora-content pre{background:#1e1e1e}.editora-content blockquote{margin:1em 0;padding-left:1em;border-left:4px solid #ddd;color:#666}.editora-theme-dark .editora-content blockquote{border-left-color:#3c3c3c;color:#9a9a9a}.editora-floating-toolbar{position:absolute;padding:4px;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-floating-toolbar{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-statusbar{display:flex;align-items:center;gap:12px;padding:6px 12px;background:#f5f5f5;border-top:1px solid #ddd;font-size:12px;color:#666}.editora-theme-dark .editora-statusbar{background:#252526;border-top-color:#3c3c3c;color:#9a9a9a}.editora-statusbar-item{white-space:nowrap}.editora-statusbar-separator{color:#ddd}.editora-theme-dark .editora-statusbar-separator{color:#3c3c3c}.editora-editor[readonly] .editora-content{background:#fafafa;cursor:not-allowed}.editora-theme-dark.editora-editor[readonly] .editora-content{background:#1a1a1a}.editora-editor:focus-within{border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.editora-theme-dark.editora-editor:focus-within{border-color:#4db8ff;box-shadow:0 0 0 3px #4db8ff1a}.editora-editor[disabled]{opacity:.6;pointer-events:none}@media(max-width:768px){.editora-toolbar{padding:4px}.editora-toolbar-button{min-width:28px;min-height:28px;padding:4px 8px;font-size:12px}.editora-content{padding:12px}}.editora-content ::selection{background:#06c3}.editora-theme-dark .editora-content ::selection{background:#4db8ff33}.editora-content table{border-collapse:collapse;width:100%;margin:1em 0}.editora-content th,.editora-content td{border:1px solid #ddd;padding:8px 12px;text-align:left}.editora-theme-dark .editora-content th,.editora-theme-dark .editora-content td{border-color:#3c3c3c}.editora-content th{background:#f5f5f5;font-weight:600}.editora-theme-dark .editora-content th{background:#252526}.editora-content img{max-width:100%;height:auto;border-radius:4px}.editora-editor.loading{opacity:.7;pointer-events:none}.editora-editor.loading:after{content:"";position:absolute;top:50%;left:50%;width:24px;height:24px;margin:-12px 0 0 -12px;border:3px solid #ddd;border-top-color:#06c;border-radius:50%;animation:editora-spin .8s linear infinite}@keyframes editora-spin{to{transform:rotate(360deg)}}';let m;function M(){const h="editora-webcomponent-styles";if(!document.getElementById(h)){const t=document.createElement("style");t.id=h,t.textContent=A,document.head.appendChild(t)}}function P(){if(!m){const h=I.__globalPluginLoader;h?m=h:m=new T}return m}function N(h){const t=P();Object.entries(h).forEach(([e,o])=>{t.register(e,o)})}class I extends HTMLElement{constructor(){if(super(),this.config={},this.isInitialized=!1,this.pluginLoader=P(),M(),!this.hasAttribute("data-initial-content")){const t=this.innerHTML.trim();t&&this.setAttribute("data-initial-content",t)}}static get observedAttributes(){return["height","width","menubar","plugins","toolbar","toolbar-items","readonly","disabled","theme","placeholder","autofocus","language","spellcheck"]}connectedCallback(){this.config=this.resolveConfig(),setTimeout(()=>{this.initialize()},0)}disconnectedCallback(){this.destroy()}attributeChangedCallback(t,e,o){e!==o&&(this.config=this.resolveConfig(),this.handleAttributeChange(t,o))}setConfig(t){this.jsConfig=t,this.config=this.resolveConfig(),this.isConnected&&(this.destroy(),this.initialize())}initialize(){if(this.querySelector(".editora-toolbar")||this.isInitialized)return;this.setAttribute("data-editora-editor","true"),this.config.height&&(this.style.height=typeof this.config.height=="number"?`${this.config.height}px`:this.config.height),this.config.width&&(this.style.width=typeof this.config.width=="number"?`${this.config.width}px`:this.config.width),this.classList.add("editora-editor"),this.config.theme&&this.classList.add(`editora-theme-${this.config.theme}`);const t=this.loadPlugins();t.forEach(o=>{if(o.init&&typeof o.init=="function")try{o.init()}catch(i){console.error(`[RichTextEditor] Error initializing plugin ${o.name}:`,i)}});const e=this.getAttribute("data-initial-content")||"";this.engine=new w({content:e,plugins:t,readonly:this.config.readonly}),this.createUI(t,e),this.setupEventListeners(),this.isInitialized=!0,this.dispatchEvent(new CustomEvent("editor-ready",{detail:{api:this.getAPI()},bubbles:!0}))}getInitialContent(){if(this.config.content)return this.config.content;const t=this.querySelector("[slot]");return t?t.innerHTML:this.hasChildNodes()?Array.from(this.childNodes).map(o=>o.nodeType===Node.TEXT_NODE?o.textContent:o.nodeType===Node.ELEMENT_NODE?o.outerHTML:"").join("").trim():""}loadPlugins(){const t=[];if(this.config.plugins&&(typeof this.config.plugins=="string"&&this.config.plugins.length>0||Array.isArray(this.config.plugins)&&this.config.plugins.length>0))if(typeof this.config.plugins=="string"){const o=this.pluginLoader.parsePluginString(this.config.plugins);t.push(...o)}else Array.isArray(this.config.plugins)&&this.config.plugins.forEach(o=>{if(typeof o=="string"){const i=this.pluginLoader.load(o);i&&t.push(i)}else t.push(o)});else{const o=this.pluginLoader.getRegisteredPluginNames(),i=this.pluginLoader.loadMultiple(o);t.push(...i)}return t}createUI(t,e){const o=this.querySelector('[slot="toolbar"]'),i=this.querySelector('[slot="statusbar"]');if(this.innerHTML="",this.config.toolbar!==!1&&!o){this.toolbarElement=document.createElement("div"),this.toolbarElement.className="editora-toolbar-container",this.appendChild(this.toolbarElement);const n=this.config.toolbarItems||this.config.toolbar;this.toolbar=new k({items:typeof n=="string"?n:void 0,sticky:this.config.toolbar&&typeof this.config.toolbar=="object"?this.config.toolbar.sticky:!1,position:"top"},t,this.pluginLoader),this.toolbar.setCommandHandler((s,r)=>{var b,p;if(this.contentElement){this.contentElement.focus();const c=window.getSelection();if(!c||c.rangeCount===0||!this.contentElement.contains(c.anchorNode)){const a=document.createRange(),l=this.contentElement.lastChild||this.contentElement;l.nodeType===Node.TEXT_NODE?a.setStart(l,((b=l.textContent)==null?void 0:b.length)||0):l.nodeType===Node.ELEMENT_NODE?(a.selectNodeContents(l),a.collapse(!1)):a.setStart(this.contentElement,0),a.collapse(!0),c==null||c.removeAllRanges(),c==null||c.addRange(a)}}const d=t.find(c=>c.commands&&c.commands[s]);if(d&&d.commands){const c=d.commands[s];if(typeof c=="function")try{return c(s==="toggleFullscreen"?this:r)}catch(a){return console.error(`[RichTextEditor] Error executing native command ${s}:`,a),!1}}return((p=this.engine)==null?void 0:p.execCommand(s,r))||!1}),this.toolbar.render(this.toolbarElement)}else o&&this.appendChild(o);this.contentElement=document.createElement("div"),this.contentElement.className="editora-content rte-content",this.contentElement.contentEditable=this.config.readonly?"false":"true",this.contentElement.setAttribute("role","textbox"),this.contentElement.setAttribute("aria-multiline","true"),this.config.placeholder&&this.contentElement.setAttribute("data-placeholder",this.config.placeholder);try{document.execCommand("defaultParagraphSeparator",!1,"p")}catch(n){console.warn("defaultParagraphSeparator not supported:",n)}if(e){const n=document.createElement("div");n.innerHTML=e.trim(),!Array.from(n.childNodes).some(r=>{if(r.nodeType===Node.ELEMENT_NODE){const d=r.tagName;return["P","DIV","H1","H2","H3","H4","H5","H6","UL","OL","BLOCKQUOTE","PRE"].includes(d)}return!1})&&e.trim()?this.contentElement.innerHTML=`<p>${e.trim()}</p>`:this.contentElement.innerHTML=e}else this.config.placeholder?this.contentElement.innerHTML="":this.contentElement.innerHTML="<p><br></p>";this.appendChild(this.contentElement),this.config.toolbar&&typeof this.config.toolbar=="object"&&this.config.toolbar.floating&&(this.floatingToolbar=new v({enabled:!0}),this.floatingToolbar.create(this)),i?this.appendChild(i):this.config.statusbar&&(this.statusBarElement=document.createElement("div"),this.statusBarElement.className="editora-statusbar-container",this.appendChild(this.statusBarElement),this.statusBar=new L({position:"bottom"}),this.statusBar.create(this.statusBarElement)),this.config.autofocus&&setTimeout(()=>{var n;return(n=this.contentElement)==null?void 0:n.focus()},0)}setupEventListeners(){!this.contentElement||!this.engine||(this.contentElement.addEventListener("input",()=>{const t=this.contentElement.innerHTML;if(this.dispatchEvent(new CustomEvent("content-change",{detail:{html:t},bubbles:!0})),this.statusBar){const e=this.contentElement.textContent||"",o=e.trim().split(/\s+/).filter(Boolean).length,i=e.length;this.statusBar.update({wordCount:o,charCount:i})}}),this.contentElement.addEventListener("focus",()=>{this.dispatchEvent(new Event("editor-focus",{bubbles:!0}))}),this.contentElement.addEventListener("blur",()=>{this.dispatchEvent(new Event("editor-blur",{bubbles:!0}))}),this.floatingToolbar&&document.addEventListener("selectionchange",()=>{this.updateFloatingToolbar()}))}updateFloatingToolbar(){if(!this.floatingToolbar)return;const t=window.getSelection();if(!t||t.rangeCount===0){this.floatingToolbar.hide();return}const e=t.getRangeAt(0);if(e.collapsed){this.floatingToolbar.hide();return}const o=e.getBoundingClientRect();this.floatingToolbar.show(o.left,o.top-40)}handleAttributeChange(t,e){switch(t){case"readonly":this.contentElement&&(this.contentElement.contentEditable=e==="true"?"false":"true"),this.engine&&this.engine.setReadonly(e==="true");break;case"theme":this.classList.forEach(o=>{o.startsWith("editora-theme-")&&this.classList.remove(o)}),e&&this.classList.add(`editora-theme-${e}`);break;case"placeholder":this.contentElement&&this.contentElement.setAttribute("data-placeholder",e);break;case"toolbar":case"plugins":this.isConnected&&(this.destroy(),this.initialize());break}}resolveConfig(){const t={};for(let e=0;e<this.attributes.length;e++){const o=this.attributes[e];t[o.name]=o.value}return f.resolve({jsConfig:this.jsConfig,attributes:t})}getAPI(){return{getContent:()=>{var t;return((t=this.contentElement)==null?void 0:t.innerHTML)||""},setContent:t=>{this.contentElement&&(this.contentElement.innerHTML=t)},execCommand:(t,e)=>{var o;return((o=this.engine)==null?void 0:o.execCommand(t,e))||!1},focus:()=>{var t;(t=this.contentElement)==null||t.focus()},blur:()=>{var t;(t=this.contentElement)==null||t.blur()},destroy:()=>{this.destroy()},on:(t,e)=>(this.addEventListener(t,e),()=>this.removeEventListener(t,e)),getConfig:()=>({...this.config}),setReadonly:t=>{this.setAttribute("readonly",t.toString())}}}destroy(){var t,e,o,i;(t=this.engine)==null||t.destroy(),(e=this.toolbar)==null||e.destroy(),(o=this.floatingToolbar)==null||o.destroy(),(i=this.statusBar)==null||i.destroy(),this.innerHTML="",this.isInitialized=!1,this.dispatchEvent(new Event("editor-destroy",{bubbles:!0}))}getContent(){var t;return((t=this.contentElement)==null?void 0:t.innerHTML)||""}setContent(t){this.contentElement&&(this.contentElement.innerHTML=t)}execCommand(t,e){var o;return((o=this.engine)==null?void 0:o.execCommand(t,e))||!1}focus(){var t;(t=this.contentElement)==null||t.focus()}blur(){var t;(t=this.contentElement)==null||t.blur()}}exports.CommandRegistry=C;exports.ConfigResolver=f;exports.EditorEngine=w;exports.EditorState=g;exports.FloatingToolbar=v;exports.PluginLoader=T;exports.PluginManager=x;exports.RichTextEditorElement=I;exports.Schema=E;exports.StatusBar=L;exports.ToolbarRenderer=k;exports.initWebComponent=N; | ||
| //# sourceMappingURL=index-BK2lHfHK.js.map |
Sorry, the diff of this file is too big to display
| class m { | ||
| constructor(t, e, o) { | ||
| this.doc = t, this.selection = e, this.schema = o; | ||
| } | ||
| static create(t, e) { | ||
| const o = e || t.node("doc", {}, [t.node("paragraph")]); | ||
| return new m(o, { anchor: 0, head: 0 }, t); | ||
| } | ||
| apply(t, e) { | ||
| return new m(t, e || this.selection, this.schema); | ||
| } | ||
| } | ||
| class E { | ||
| constructor(t, e) { | ||
| this.nodes = new Map(Object.entries(t)), this.marks = new Map(Object.entries(e)); | ||
| } | ||
| node(t, e, o) { | ||
| return { type: t, attrs: e, content: o }; | ||
| } | ||
| text(t, e) { | ||
| return { type: "text", text: t, marks: e }; | ||
| } | ||
| } | ||
| class C { | ||
| constructor() { | ||
| this.plugins = [], this.pluginConfigs = /* @__PURE__ */ new Map(); | ||
| } | ||
| register(t, e) { | ||
| if (this.plugins.push(t), e && this.pluginConfigs.set(t.name, e), t.initialize) { | ||
| const o = this.pluginConfigs.get(t.name) || t.config; | ||
| t.initialize(o); | ||
| } | ||
| } | ||
| unregister(t) { | ||
| const e = this.plugins.findIndex((o) => o.name === t); | ||
| if (e > -1) { | ||
| const o = this.plugins[e]; | ||
| o.destroy && o.destroy(), this.plugins.splice(e, 1), this.pluginConfigs.delete(t); | ||
| } | ||
| } | ||
| getPlugin(t) { | ||
| return this.plugins.find((e) => e.name === t); | ||
| } | ||
| getPluginConfig(t) { | ||
| return this.pluginConfigs.get(t); | ||
| } | ||
| buildSchema() { | ||
| const t = {}, e = {}; | ||
| return this.plugins.forEach((o) => { | ||
| o.nodes && Object.assign(t, o.nodes), o.marks && Object.assign(e, o.marks); | ||
| }), new E(t, e); | ||
| } | ||
| getCommands() { | ||
| const t = {}; | ||
| return this.plugins.forEach((e) => { | ||
| e.commands && Object.assign(t, e.commands); | ||
| }), t; | ||
| } | ||
| getToolbarItems() { | ||
| return this.plugins.flatMap((t) => t.toolbar || []); | ||
| } | ||
| /** | ||
| * Execute plugin command with mode awareness | ||
| */ | ||
| async executePluginCommand(t, e, ...o) { | ||
| const i = this.getPlugin(t); | ||
| if (!i) | ||
| throw new Error(`Plugin not found: ${t}`); | ||
| const n = this.getPluginConfig(t) || i.config || {}, s = n.mode || "local"; | ||
| try { | ||
| switch (s) { | ||
| case "local": | ||
| return i.executeLocal ? i.executeLocal(e, ...o) : null; | ||
| case "api": | ||
| if (!i.executeAPI) | ||
| throw new Error(`Plugin ${t} does not support API mode`); | ||
| return await i.executeAPI(e, ...o); | ||
| case "hybrid": | ||
| if (i.executeHybrid) | ||
| return await i.executeHybrid(e, ...o); | ||
| try { | ||
| if (i.executeAPI) | ||
| return await i.executeAPI(e, ...o); | ||
| } catch (r) { | ||
| if (console.warn(`API execution failed for ${t}, falling back to local`, r), i.executeLocal && n.fallbackToLocal !== !1) | ||
| return i.executeLocal(e, ...o); | ||
| throw r; | ||
| } | ||
| break; | ||
| default: | ||
| throw new Error(`Unknown plugin mode: ${s}`); | ||
| } | ||
| } catch (r) { | ||
| throw console.error(`Error executing command ${e} on plugin ${t}:`, r), r; | ||
| } | ||
| } | ||
| /** | ||
| * Destroy all plugins | ||
| */ | ||
| async destroyAll() { | ||
| const t = this.plugins.filter((e) => e.destroy).map((e) => e.destroy()); | ||
| await Promise.all(t), this.plugins = [], this.pluginConfigs.clear(); | ||
| } | ||
| } | ||
| class w { | ||
| constructor(t = {}) { | ||
| this.commands = /* @__PURE__ */ new Map(), Object.entries(t).forEach(([e, o]) => { | ||
| this.register(e, o); | ||
| }); | ||
| } | ||
| /** | ||
| * Register a command | ||
| */ | ||
| register(t, e) { | ||
| this.commands.has(t) && console.warn(`Command ${t} is being overwritten`), this.commands.set(t, e); | ||
| } | ||
| /** | ||
| * Unregister a command | ||
| */ | ||
| unregister(t) { | ||
| this.commands.delete(t); | ||
| } | ||
| /** | ||
| * Get a command handler | ||
| */ | ||
| get(t) { | ||
| return this.commands.get(t); | ||
| } | ||
| /** | ||
| * Check if command exists | ||
| */ | ||
| has(t) { | ||
| return this.commands.has(t); | ||
| } | ||
| /** | ||
| * Get all command names | ||
| */ | ||
| getCommandNames() { | ||
| return Array.from(this.commands.keys()); | ||
| } | ||
| /** | ||
| * Clear all commands | ||
| */ | ||
| clear() { | ||
| this.commands.clear(); | ||
| } | ||
| } | ||
| class k { | ||
| constructor(t = {}) { | ||
| this.listeners = /* @__PURE__ */ new Map(), this.isReadonly = !1, this.isDestroyed = !1, this.isReadonly = t.readonly || !1, this.pluginManager = new C(), t.plugins && Array.isArray(t.plugins) && t.plugins.forEach((o) => this.pluginManager.register(o)); | ||
| const e = this.pluginManager.buildSchema(); | ||
| this.state = m.create(e), this.commandRegistry = new w(this.pluginManager.getCommands()); | ||
| } | ||
| /** | ||
| * Execute a command | ||
| */ | ||
| execCommand(t, e) { | ||
| if (this.isReadonly) | ||
| return console.warn("Cannot execute commands in readonly mode"), !1; | ||
| if (this.isDestroyed) | ||
| return console.warn("Cannot execute commands on destroyed editor"), !1; | ||
| const o = this.commandRegistry.get(t); | ||
| if (!o) | ||
| return console.warn(`Command not found: ${t}`), !1; | ||
| let i; | ||
| return e !== void 0 ? i = o(this.state, e) : i = o(this.state), i ? (this.setState(i), this.emit("change", this.state), !0) : !1; | ||
| } | ||
| /** | ||
| * Update editor state | ||
| */ | ||
| setState(t) { | ||
| this.isDestroyed || (this.state = t, this.emit("stateChange", t)); | ||
| } | ||
| /** | ||
| * Get current state | ||
| */ | ||
| getState() { | ||
| return this.state; | ||
| } | ||
| /** | ||
| * Set readonly mode | ||
| */ | ||
| setReadonly(t) { | ||
| this.isReadonly = t, this.emit("readonlyChange", t); | ||
| } | ||
| /** | ||
| * Check if readonly | ||
| */ | ||
| isReadOnly() { | ||
| return this.isReadonly; | ||
| } | ||
| /** | ||
| * Event emitter | ||
| */ | ||
| on(t, e) { | ||
| return this.listeners.has(t) || this.listeners.set(t, []), this.listeners.get(t).push(e), () => { | ||
| const o = this.listeners.get(t); | ||
| if (o) { | ||
| const i = o.indexOf(e); | ||
| i > -1 && o.splice(i, 1); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Emit event | ||
| */ | ||
| emit(t, ...e) { | ||
| const o = this.listeners.get(t); | ||
| o && o.forEach((i) => { | ||
| try { | ||
| i(...e); | ||
| } catch (n) { | ||
| console.error(`Error in ${t} handler:`, n); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Destroy editor instance | ||
| */ | ||
| destroy() { | ||
| this.isDestroyed || (this.isDestroyed = !0, this.listeners.clear(), this.emit("destroy")); | ||
| } | ||
| /** | ||
| * Check if destroyed | ||
| */ | ||
| isEditorDestroyed() { | ||
| return this.isDestroyed; | ||
| } | ||
| } | ||
| class v { | ||
| // PluginLoader instance to get all registered plugins | ||
| constructor(t, e, o) { | ||
| this.config = t, this.plugins = e, this.pluginLoader = o; | ||
| } | ||
| /** | ||
| * Set command handler for toolbar buttons | ||
| */ | ||
| setCommandHandler(t) { | ||
| this.commandHandler = t; | ||
| } | ||
| /** | ||
| * Parse toolbar string into button groups | ||
| */ | ||
| parseToolbarString(t) { | ||
| const e = [], o = t.split("|").map((r) => r.trim()), i = this.getAvailableToolbarItems(), n = /* @__PURE__ */ new Map(); | ||
| i.forEach((r) => { | ||
| r.command && n.set(r.command, r), r.type === "group" && r.label && n.set(r.label, r); | ||
| }); | ||
| const s = { | ||
| bold: "toggleBold", | ||
| italic: "toggleItalic", | ||
| underline: "toggleUnderline", | ||
| strikethrough: "toggleStrikethrough", | ||
| bullist: "toggleBulletList", | ||
| numlist: "toggleOrderedList", | ||
| checklist: "toggleChecklist", | ||
| link: "openLinkDialog", | ||
| image: "openImageDialog", | ||
| table: "insertTable", | ||
| anchor: "insertAnchor", | ||
| code: "toggleSourceView", | ||
| blockquote: "toggleBlockquote", | ||
| undo: "undo", | ||
| redo: "redo", | ||
| textColor: "openTextColorPicker", | ||
| backgroundColor: "openBackgroundColorPicker", | ||
| fontSize: "fontSize", | ||
| fontFamily: "setFontFamily", | ||
| lineHeight: "setLineHeight", | ||
| heading: "setBlockType", | ||
| paragraph: "setParagraph", | ||
| textAlignment: "setTextAlignment", | ||
| direction: "setDirectionLTR", | ||
| indent: "increaseIndent", | ||
| outdent: "decreaseIndent", | ||
| capitalization: "setCapitalization", | ||
| math: "insertMath", | ||
| specialCharacters: "insertSpecialCharacter", | ||
| emojis: "openEmojiDialog", | ||
| embedIframe: "openEmbedIframeDialog", | ||
| fullscreen: "toggleFullscreen", | ||
| preview: "togglePreview", | ||
| print: "print", | ||
| a11yChecker: "toggleA11yChecker", | ||
| spellCheck: "toggleSpellCheck", | ||
| comments: "addComment", | ||
| showHideComments: "toggleComments", | ||
| toggleComments: "toggleComments", | ||
| footnote: "insertFootnote", | ||
| mergeTags: "insertMergeTag", | ||
| pageBreak: "insertPageBreak", | ||
| template: "insertTemplate", | ||
| importWord: "importWord", | ||
| exportWord: "exportWord", | ||
| exportPdf: "exportPdf", | ||
| insertImage: "insertImage", | ||
| insertVideo: "insertVideo", | ||
| codeBlock: "insertCodeBlock" | ||
| }; | ||
| return o.forEach((r) => { | ||
| const d = []; | ||
| r.split(/\s+/).filter(Boolean).forEach((p) => { | ||
| if (p === "direction") { | ||
| const l = n.get("setDirectionLTR"), u = n.get("setDirectionRTL"); | ||
| l && d.push({ | ||
| id: "directionLTR", | ||
| label: l.label, | ||
| command: l.command, | ||
| icon: l.icon, | ||
| type: l.type || "button", | ||
| options: l.options | ||
| }), u && d.push({ | ||
| id: "directionRTL", | ||
| label: u.label, | ||
| command: u.command, | ||
| icon: u.icon, | ||
| type: u.type || "button", | ||
| options: u.options | ||
| }); | ||
| return; | ||
| } | ||
| if (p === "comments") { | ||
| const l = n.get("addComment"), u = n.get("toggleComments"); | ||
| l && d.push({ | ||
| id: "addComment", | ||
| label: l.label, | ||
| command: l.command, | ||
| icon: l.icon, | ||
| type: l.type || "button", | ||
| options: l.options | ||
| }), u && d.push({ | ||
| id: "toggleComments", | ||
| label: u.label, | ||
| command: u.command, | ||
| icon: u.icon, | ||
| type: u.type || "button", | ||
| options: u.options | ||
| }); | ||
| return; | ||
| } | ||
| const c = s[p] || p; | ||
| let a = n.get(c); | ||
| a || (a = n.get(p)), a && d.push({ | ||
| id: p, | ||
| label: a.label, | ||
| command: a.command, | ||
| icon: a.icon, | ||
| type: a.type === "separator" ? "separator" : a.type || "button", | ||
| options: a.options, | ||
| items: a.items | ||
| }); | ||
| }), d.length > 0 && e.push(d); | ||
| }), e; | ||
| } | ||
| /** | ||
| * Get all available toolbar items from plugins | ||
| */ | ||
| getAvailableToolbarItems() { | ||
| let t = this.plugins; | ||
| return this.pluginLoader && (t = this.pluginLoader.getRegisteredPluginNames().map((n) => this.pluginLoader.load(n)).filter((n) => n !== null)), t.flatMap((o) => o.toolbar || []); | ||
| } | ||
| /** | ||
| * Render toolbar to DOM element | ||
| */ | ||
| render(t) { | ||
| this.container = t, t.innerHTML = "", t.className = "editora-toolbar", this.config.sticky && t.classList.add("editora-toolbar-sticky"), this.config.position && t.classList.add(`editora-toolbar-${this.config.position}`); | ||
| const e = this.config.items || this.getDefaultToolbarString(), o = this.parseToolbarString(e); | ||
| o.forEach((i, n) => { | ||
| const s = document.createElement("div"); | ||
| if (s.className = "editora-toolbar-group", i.forEach((r) => { | ||
| this.appendToolbarButton(s, r); | ||
| }), t.appendChild(s), n < o.length - 1) { | ||
| const r = document.createElement("div"); | ||
| r.className = "editora-toolbar-separator", t.appendChild(r); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Append a toolbar button or group to a parent element | ||
| */ | ||
| appendToolbarButton(t, e) { | ||
| if (e.type === "separator") { | ||
| const o = document.createElement("div"); | ||
| o.className = "editora-toolbar-separator", t.appendChild(o); | ||
| } else if (e.type === "dropdown") { | ||
| const o = this.createDropdown(e); | ||
| t.appendChild(o); | ||
| } else if (e.type === "inline-menu") { | ||
| const o = this.createInlineMenu(e); | ||
| t.appendChild(o); | ||
| } else if (e.type === "group" && e.items && e.items.length) { | ||
| const o = this.createGroupButton(e); | ||
| t.appendChild(o); | ||
| } else if (e.type === "input") { | ||
| const o = this.createInput(e); | ||
| t.appendChild(o); | ||
| } else { | ||
| const o = this.createButton(e); | ||
| t.appendChild(o); | ||
| } | ||
| } | ||
| /** | ||
| * Create a toolbar button element | ||
| */ | ||
| createGroupButton(t) { | ||
| const e = document.createElement("div"); | ||
| if (e.className = "editora-toolbar-group-button", e.title = t.label, t.icon) | ||
| if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) { | ||
| const o = document.createElement("span"); | ||
| o.className = "editora-toolbar-icon", o.innerHTML = t.icon, e.appendChild(o); | ||
| } else | ||
| e.innerHTML = t.icon; | ||
| if (t.items && t.items.length) { | ||
| const o = document.createElement("div"); | ||
| o.className = "editora-toolbar-group-items", t.items.forEach((i) => { | ||
| this.appendToolbarButton(o, i); | ||
| }), e.appendChild(o); | ||
| } | ||
| return e; | ||
| } | ||
| /** | ||
| * Create a toolbar button element | ||
| */ | ||
| createInput(t) { | ||
| const e = document.createElement("input"); | ||
| return e.className = `editora-toolbar-input ${t.label.toLowerCase().replace(/\s+/g, "-")}`, e.type = "text", e.title = t.label, e.placeholder = t.placeholder || "", e.setAttribute("data-command", t.command), t.active && e.classList.add("active"), t.disabled && (e.disabled = !0), e.addEventListener("click", (o) => { | ||
| o.preventDefault(), this.commandHandler && this.commandHandler(t.command); | ||
| }), e; | ||
| } | ||
| /** | ||
| * Create a toolbar button element | ||
| */ | ||
| createButton(t) { | ||
| const e = document.createElement("button"); | ||
| if (e.className = "editora-toolbar-button", e.type = "button", e.title = t.label, e.setAttribute("data-command", t.command), t.icon) | ||
| if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) { | ||
| const o = document.createElement("span"); | ||
| o.className = "editora-toolbar-icon", o.innerHTML = t.icon, e.appendChild(o); | ||
| } else | ||
| e.innerHTML = t.icon; | ||
| else | ||
| e.textContent = t.label; | ||
| return t.active && e.classList.add("active"), t.disabled && (e.disabled = !0), e.addEventListener("click", (o) => { | ||
| o.preventDefault(), this.commandHandler && this.commandHandler(t.command); | ||
| }), e; | ||
| } | ||
| /** | ||
| * Create a dropdown element | ||
| */ | ||
| createDropdown(t) { | ||
| const e = document.createElement("div"); | ||
| e.className = "editora-toolbar-dropdown"; | ||
| const o = document.createElement("button"); | ||
| o.className = "editora-toolbar-button editora-toolbar-dropdown-trigger", o.type = "button", o.textContent = t.label; | ||
| const i = document.createElement("div"); | ||
| i.className = "editora-toolbar-dropdown-menu", i.style.display = "none", t.options && t.options.forEach((s) => { | ||
| const r = document.createElement("button"); | ||
| r.className = "editora-toolbar-dropdown-item", r.type = "button", r.textContent = s.label, r.setAttribute("data-value", s.value), r.addEventListener("click", (d) => { | ||
| d.preventDefault(), this.commandHandler && this.commandHandler(t.command, s.value), i.style.display = "none"; | ||
| }), i.appendChild(r); | ||
| }), o.addEventListener("click", (s) => { | ||
| s.preventDefault(), s.stopPropagation(); | ||
| const r = i.style.display === "block"; | ||
| i.style.display = r ? "none" : "block"; | ||
| }); | ||
| const n = (s) => { | ||
| e.contains(s.target) || (i.style.display = "none"); | ||
| }; | ||
| return document.addEventListener("click", n), e._cleanupDropdown = () => { | ||
| document.removeEventListener("click", n); | ||
| }, e.appendChild(o), e.appendChild(i), e; | ||
| } | ||
| /** | ||
| * Create an inline menu element (like dropdown but triggered by button click) | ||
| */ | ||
| createInlineMenu(t) { | ||
| const e = document.createElement("div"); | ||
| e.className = "editora-toolbar-dropdown editora-toolbar-inline-menu"; | ||
| const o = document.createElement("button"); | ||
| if (o.className = "editora-toolbar-button", o.type = "button", o.title = t.label, t.icon) | ||
| if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) { | ||
| const n = document.createElement("span"); | ||
| n.className = "editora-toolbar-icon", n.innerHTML = t.icon, o.appendChild(n); | ||
| } else | ||
| o.innerHTML = t.icon; | ||
| else | ||
| o.textContent = t.label; | ||
| const i = document.createElement("div"); | ||
| return i.className = "editora-toolbar-dropdown-menu", i.style.display = "none", t.options && t.options.forEach((n) => { | ||
| const s = document.createElement("button"); | ||
| s.className = "editora-toolbar-dropdown-item", s.type = "button", s.textContent = n.label, s.setAttribute("data-value", n.value), s.addEventListener("click", (r) => { | ||
| r.preventDefault(), r.stopPropagation(), this.commandHandler && this.commandHandler(t.command, n.value), i.style.display = "none"; | ||
| }), i.appendChild(s); | ||
| }), o.addEventListener("click", (n) => { | ||
| var r; | ||
| n.preventDefault(), n.stopPropagation(); | ||
| const s = (r = this.container) == null ? void 0 : r.querySelectorAll( | ||
| ".editora-toolbar-dropdown-menu" | ||
| ); | ||
| s == null || s.forEach((d) => { | ||
| d !== i && (d.style.display = "none"); | ||
| }), i.style.display = i.style.display === "none" ? "block" : "none"; | ||
| }), document.addEventListener("click", (n) => { | ||
| e.contains(n.target) || (i.style.display = "none"); | ||
| }), e.appendChild(o), e.appendChild(i), e; | ||
| } | ||
| /** | ||
| * Get default toolbar string if none provided | ||
| */ | ||
| getDefaultToolbarString() { | ||
| return this.getAvailableToolbarItems().map((e) => e.command).join(" "); | ||
| } | ||
| /** | ||
| * Update button state | ||
| */ | ||
| updateButtonState(t, e) { | ||
| if (!this.container) return; | ||
| const o = this.container.querySelector( | ||
| `[data-command="${t}"]` | ||
| ); | ||
| o && (e.active !== void 0 && o.classList.toggle("active", e.active), e.disabled !== void 0 && (o.disabled = e.disabled)); | ||
| } | ||
| /** | ||
| * Destroy toolbar | ||
| */ | ||
| destroy() { | ||
| this.container && (this.container.querySelectorAll(".editora-toolbar-dropdown").forEach((e) => { | ||
| const o = e._cleanupDropdown; | ||
| o && o(); | ||
| }), this.container.innerHTML = ""), this.commandHandler = void 0; | ||
| } | ||
| } | ||
| class L { | ||
| constructor(t) { | ||
| this.visible = !1, this.config = t; | ||
| } | ||
| /** | ||
| * Create and mount floating toolbar | ||
| */ | ||
| create(t) { | ||
| const e = document.createElement("div"); | ||
| return e.className = "editora-floating-toolbar", e.style.display = "none", e.style.position = "absolute", e.style.zIndex = "1000", this.container = e, t.appendChild(e), e; | ||
| } | ||
| /** | ||
| * Show toolbar at position | ||
| */ | ||
| show(t, e) { | ||
| this.container && (this.container.style.display = "block", this.container.style.left = `${t}px`, this.container.style.top = `${e}px`, this.visible = !0); | ||
| } | ||
| /** | ||
| * Hide toolbar | ||
| */ | ||
| hide() { | ||
| this.container && (this.container.style.display = "none", this.visible = !1); | ||
| } | ||
| /** | ||
| * Update position | ||
| */ | ||
| updatePosition(t, e) { | ||
| !this.container || !this.visible || (this.container.style.left = `${t}px`, this.container.style.top = `${e}px`); | ||
| } | ||
| /** | ||
| * Check if visible | ||
| */ | ||
| isVisible() { | ||
| return this.visible; | ||
| } | ||
| /** | ||
| * Destroy floating toolbar | ||
| */ | ||
| destroy() { | ||
| this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this.container = void 0, this.visible = !1; | ||
| } | ||
| } | ||
| class T { | ||
| constructor(t = {}) { | ||
| this.statusInfo = {}, this.config = t; | ||
| } | ||
| /** | ||
| * Create and mount status bar | ||
| */ | ||
| create(t) { | ||
| const e = document.createElement("div"); | ||
| return e.className = "editora-statusbar", this.config.position && e.classList.add(`editora-statusbar-${this.config.position}`), this.container = e, t.appendChild(e), e; | ||
| } | ||
| /** | ||
| * Update status information | ||
| */ | ||
| update(t) { | ||
| this.statusInfo = { ...this.statusInfo, ...t }, this.render(); | ||
| } | ||
| /** | ||
| * Render status bar content | ||
| */ | ||
| render() { | ||
| if (!this.container) return; | ||
| this.container.innerHTML = ""; | ||
| const t = []; | ||
| this.statusInfo.wordCount !== void 0 && t.push(`Words: ${this.statusInfo.wordCount}`), this.statusInfo.charCount !== void 0 && t.push(`Characters: ${this.statusInfo.charCount}`), this.statusInfo.lineCount !== void 0 && t.push(`Lines: ${this.statusInfo.lineCount}`), this.statusInfo.language && t.push(`Language: ${this.statusInfo.language}`), this.statusInfo.custom && Object.entries(this.statusInfo.custom).forEach(([e, o]) => { | ||
| t.push(`${e}: ${o}`); | ||
| }), t.forEach((e, o) => { | ||
| const i = document.createElement("span"); | ||
| if (i.className = "editora-statusbar-item", i.textContent = e, this.container.appendChild(i), o < t.length - 1) { | ||
| const n = document.createElement("span"); | ||
| n.className = "editora-statusbar-separator", n.textContent = "|", this.container.appendChild(n); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Destroy status bar | ||
| */ | ||
| destroy() { | ||
| this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this.container = void 0; | ||
| } | ||
| } | ||
| const y = class y { | ||
| /** | ||
| * Resolve configuration from multiple sources with priority | ||
| */ | ||
| static resolve(t) { | ||
| const e = {}; | ||
| if (Object.assign(e, this.EDITOR_DEFAULTS), t.pluginDefaults && Object.assign(e, t.pluginDefaults), t.attributes) { | ||
| const o = this.parseAttributes(t.attributes); | ||
| Object.assign(e, o); | ||
| } | ||
| return t.jsConfig && Object.assign(e, t.jsConfig), e; | ||
| } | ||
| /** | ||
| * Parse web component attributes | ||
| */ | ||
| static parseAttributes(t) { | ||
| const e = {}; | ||
| for (const [o, i] of Object.entries(t)) { | ||
| const n = this.kebabToCamel(o); | ||
| e[n] = this.parseAttributeValue(i); | ||
| } | ||
| return e; | ||
| } | ||
| /** | ||
| * Parse attribute value to appropriate type | ||
| */ | ||
| static parseAttributeValue(t) { | ||
| if (t === "true") return !0; | ||
| if (t === "false") return !1; | ||
| if (/^\d+$/.test(t)) return parseInt(t, 10); | ||
| if (/^\d+\.\d+$/.test(t)) return parseFloat(t); | ||
| if (t.startsWith("{") || t.startsWith("[")) | ||
| try { | ||
| return JSON.parse(t); | ||
| } catch (e) { | ||
| return t; | ||
| } | ||
| return t; | ||
| } | ||
| /** | ||
| * Convert kebab-case to camelCase | ||
| */ | ||
| static kebabToCamel(t) { | ||
| return t.replace(/-([a-z])/g, (e, o) => o.toUpperCase()); | ||
| } | ||
| /** | ||
| * Validate configuration | ||
| */ | ||
| static validate(t) { | ||
| const e = []; | ||
| return t.height !== void 0 && typeof t.height == "number" && t.height < 0 && e.push("height must be a positive number"), t.width !== void 0 && typeof t.width == "number" && t.width < 0 && e.push("width must be a positive number"), t.plugins !== void 0 && !Array.isArray(t.plugins) && typeof t.plugins != "string" && e.push("plugins must be an array or string"), t.theme !== void 0 && typeof t.theme != "string" && e.push("theme must be a string"), { | ||
| valid: e.length === 0, | ||
| errors: e | ||
| }; | ||
| } | ||
| /** | ||
| * Get default configuration | ||
| */ | ||
| static getDefaults() { | ||
| return { ...this.EDITOR_DEFAULTS }; | ||
| } | ||
| /** | ||
| * Merge configurations (deep merge) | ||
| */ | ||
| static merge(...t) { | ||
| const e = {}; | ||
| for (const o of t) | ||
| for (const [i, n] of Object.entries(o)) | ||
| n != null && (typeof n == "object" && !Array.isArray(n) && e[i] ? e[i] = this.merge(e[i], n) : e[i] = n); | ||
| return e; | ||
| } | ||
| }; | ||
| y.EDITOR_DEFAULTS = { | ||
| height: 400, | ||
| width: "100%", | ||
| readonly: !1, | ||
| disabled: !1, | ||
| menubar: !0, | ||
| toolbar: !0, | ||
| plugins: [], | ||
| theme: "light", | ||
| content: "", | ||
| placeholder: "Start typing...", | ||
| autofocus: !1, | ||
| autosave: !1, | ||
| spellcheck: !1, | ||
| language: "en" | ||
| }; | ||
| let b = y; | ||
| class P { | ||
| constructor() { | ||
| this.loadedPlugins = /* @__PURE__ */ new Map(), this.pluginRegistry = /* @__PURE__ */ new Map(); | ||
| } | ||
| /** | ||
| * Register a plugin factory | ||
| */ | ||
| register(t, e) { | ||
| this.pluginRegistry.set(t, e); | ||
| } | ||
| /** | ||
| * Load a plugin by name | ||
| */ | ||
| load(t, e) { | ||
| if (this.loadedPlugins.has(t)) | ||
| return this.loadedPlugins.get(t); | ||
| const o = this.pluginRegistry.get(t); | ||
| if (!o) | ||
| return console.warn(`Plugin not found: ${t}`), null; | ||
| const i = o(); | ||
| return e && this.applyPluginConfig(i, e), this.loadedPlugins.set(t, i), i; | ||
| } | ||
| /** | ||
| * Load multiple plugins | ||
| */ | ||
| loadMultiple(t, e) { | ||
| return t.map((o) => this.load(o, e)).filter((o) => o !== null); | ||
| } | ||
| /** | ||
| * Parse plugin string "lists link image media" | ||
| */ | ||
| parsePluginString(t, e) { | ||
| const o = t.split(/\s+/).filter(Boolean); | ||
| return this.loadMultiple(o, e); | ||
| } | ||
| /** | ||
| * Apply configuration to plugin | ||
| */ | ||
| applyPluginConfig(t, e) { | ||
| t.__pluginConfig = e; | ||
| } | ||
| /** | ||
| * Unload a plugin | ||
| */ | ||
| unload(t) { | ||
| this.loadedPlugins.delete(t); | ||
| } | ||
| /** | ||
| * Clear all loaded plugins | ||
| */ | ||
| clear() { | ||
| this.loadedPlugins.clear(); | ||
| } | ||
| /** | ||
| * Get all loaded plugin names | ||
| */ | ||
| getLoadedPluginNames() { | ||
| return Array.from(this.loadedPlugins.keys()); | ||
| } | ||
| /** | ||
| * Get all registered plugin names (available for loading) | ||
| */ | ||
| getRegisteredPluginNames() { | ||
| return Array.from(this.pluginRegistry.keys()); | ||
| } | ||
| /** | ||
| * Check if plugin is loaded | ||
| */ | ||
| isLoaded(t) { | ||
| return this.loadedPlugins.has(t); | ||
| } | ||
| } | ||
| const I = '.editora-editor{display:flex;flex-direction:column;border:1px solid #ddd;border-radius:4px;background:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;overflow:hidden}.editora-editor *{box-sizing:border-box}.editora-theme-light{background:#fff;color:#333}.editora-theme-dark{background:#1e1e1e;color:#d4d4d4;border-color:#3c3c3c}.editora-toolbar{display:flex;align-items:center;gap:4px;padding:8px;background:#f5f5f5;border-bottom:1px solid #ddd;flex-wrap:wrap}.editora-theme-dark .editora-toolbar{background:#252526;border-bottom-color:#3c3c3c}.editora-toolbar-sticky{position:sticky;top:0;z-index:100}.editora-toolbar-group{display:flex;align-items:center;gap:2px}.editora-toolbar-button{padding:6px 12px;border:1px solid #ccc;background:#fff;cursor:pointer;border-radius:3px;font-weight:600;font-size:14px;height:30px;display:flex;align-items:center;white-space:nowrap}.editora-toolbar-input.font-size{width:40px;padding:.25rem;text-align:center;font-size:14px;background:#fff;border:1px solid var(--rte-color-border-light);border-radius:var(--rte-radius-sm)}.editora-toolbar-group-items{display:flex;align-items:center;border:1px solid #ccc;.editora-toolbar-button{border:none;border-radius:0;&:first-child{border-right:1px solid #ccc;border-top-left-radius:3px;border-bottom-left-radius:3px}&:last-child{border-left:1px solid #ccc;border-top-right-radius:3px;border-bottom-right-radius:3px}}}.editora-theme-dark .editora-toolbar-button{color:#d4d4d4}.editora-toolbar-button:hover{background:#e0e0e0;border-color:#ccc}.editora-theme-dark .editora-toolbar-button:hover{background:#37373d;border-color:#555}.editora-toolbar-button:active,.editora-toolbar-button.active{background:#d0d0d0;border-color:#999}.editora-theme-dark .editora-toolbar-button:active,.editora-theme-dark .editora-toolbar-button.active{background:#2a2d2e;border-color:#666}.editora-toolbar-button:disabled{opacity:.5;cursor:not-allowed}.editora-toolbar-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;line-height:1}.editora-toolbar-button svg,.editora-toolbar-icon svg{width:24px;height:24px;display:block}.editora-toolbar-separator{width:1px;height:24px;background:#ddd;margin:0 4px}.editora-theme-dark .editora-toolbar-separator{background:#3c3c3c}.editora-toolbar-dropdown{position:relative}.editora-toolbar-dropdown-menu{position:absolute;top:100%;left:0;min-width:150px;margin-top:4px;padding:4px 0;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-toolbar-dropdown-menu{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-toolbar-dropdown-item{display:block;width:100%;padding:8px 12px;border:none;background:transparent;color:#333;text-align:left;cursor:pointer;font-size:13px;transition:background .15s ease}.editora-theme-dark .editora-toolbar-dropdown-item{color:#d4d4d4}.editora-toolbar-dropdown-item:hover{background:#f5f5f5}.editora-theme-dark .editora-toolbar-dropdown-item:hover{background:#37373d}.editora-content{flex:1;min-height:200px;padding:16px;outline:none;overflow-y:auto;line-height:1.6}.editora-content:empty:before{content:attr(data-placeholder);color:#999;pointer-events:none}.editora-theme-dark .editora-content:empty:before{color:#6a6a6a}.editora-content h1{font-size:2em;margin:.67em 0;font-weight:600}.editora-content h2{font-size:1.5em;margin:.75em 0;font-weight:600}.editora-content h3{font-size:1.17em;margin:.83em 0;font-weight:600}.editora-content p{margin:1em 0}.editora-content ul,.editora-content ol{margin:1em 0;padding-left:2em}.editora-content a{color:#06c;text-decoration:underline}.editora-theme-dark .editora-content a{color:#4db8ff}.editora-content code{padding:2px 4px;background:#f5f5f5;border-radius:3px;font-family:Monaco,Menlo,Consolas,monospace;font-size:.9em}.editora-theme-dark .editora-content code{background:#1e1e1e}.editora-content pre{padding:12px;background:#f5f5f5;border-radius:4px;overflow-x:auto;margin:1em 0}.editora-theme-dark .editora-content pre{background:#1e1e1e}.editora-content blockquote{margin:1em 0;padding-left:1em;border-left:4px solid #ddd;color:#666}.editora-theme-dark .editora-content blockquote{border-left-color:#3c3c3c;color:#9a9a9a}.editora-floating-toolbar{position:absolute;padding:4px;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-floating-toolbar{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-statusbar{display:flex;align-items:center;gap:12px;padding:6px 12px;background:#f5f5f5;border-top:1px solid #ddd;font-size:12px;color:#666}.editora-theme-dark .editora-statusbar{background:#252526;border-top-color:#3c3c3c;color:#9a9a9a}.editora-statusbar-item{white-space:nowrap}.editora-statusbar-separator{color:#ddd}.editora-theme-dark .editora-statusbar-separator{color:#3c3c3c}.editora-editor[readonly] .editora-content{background:#fafafa;cursor:not-allowed}.editora-theme-dark.editora-editor[readonly] .editora-content{background:#1a1a1a}.editora-editor:focus-within{border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.editora-theme-dark.editora-editor:focus-within{border-color:#4db8ff;box-shadow:0 0 0 3px #4db8ff1a}.editora-editor[disabled]{opacity:.6;pointer-events:none}@media(max-width:768px){.editora-toolbar{padding:4px}.editora-toolbar-button{min-width:28px;min-height:28px;padding:4px 8px;font-size:12px}.editora-content{padding:12px}}.editora-content ::selection{background:#06c3}.editora-theme-dark .editora-content ::selection{background:#4db8ff33}.editora-content table{border-collapse:collapse;width:100%;margin:1em 0}.editora-content th,.editora-content td{border:1px solid #ddd;padding:8px 12px;text-align:left}.editora-theme-dark .editora-content th,.editora-theme-dark .editora-content td{border-color:#3c3c3c}.editora-content th{background:#f5f5f5;font-weight:600}.editora-theme-dark .editora-content th{background:#252526}.editora-content img{max-width:100%;height:auto;border-radius:4px}.editora-editor.loading{opacity:.7;pointer-events:none}.editora-editor.loading:after{content:"";position:absolute;top:50%;left:50%;width:24px;height:24px;margin:-12px 0 0 -12px;border:3px solid #ddd;border-top-color:#06c;border-radius:50%;animation:editora-spin .8s linear infinite}@keyframes editora-spin{to{transform:rotate(360deg)}}'; | ||
| let g; | ||
| function A() { | ||
| const h = "editora-webcomponent-styles"; | ||
| if (!document.getElementById(h)) { | ||
| const t = document.createElement("style"); | ||
| t.id = h, t.textContent = I, document.head.appendChild(t); | ||
| } | ||
| } | ||
| function x() { | ||
| if (!g) { | ||
| const h = M.__globalPluginLoader; | ||
| h ? g = h : g = new P(); | ||
| } | ||
| return g; | ||
| } | ||
| function N(h) { | ||
| const t = x(); | ||
| Object.entries(h).forEach(([e, o]) => { | ||
| t.register(e, o); | ||
| }); | ||
| } | ||
| class M extends HTMLElement { | ||
| constructor() { | ||
| if (super(), this.config = {}, this.isInitialized = !1, this.pluginLoader = x(), A(), !this.hasAttribute("data-initial-content")) { | ||
| const t = this.innerHTML.trim(); | ||
| t && this.setAttribute("data-initial-content", t); | ||
| } | ||
| } | ||
| // Observed attributes for reactive updates | ||
| static get observedAttributes() { | ||
| return [ | ||
| "height", | ||
| "width", | ||
| "menubar", | ||
| "plugins", | ||
| "toolbar", | ||
| "toolbar-items", | ||
| "readonly", | ||
| "disabled", | ||
| "theme", | ||
| "placeholder", | ||
| "autofocus", | ||
| "language", | ||
| "spellcheck" | ||
| ]; | ||
| } | ||
| /** | ||
| * Called when element is added to DOM | ||
| */ | ||
| connectedCallback() { | ||
| this.config = this.resolveConfig(), setTimeout(() => { | ||
| this.initialize(); | ||
| }, 0); | ||
| } | ||
| /** | ||
| * Called when element is removed from DOM | ||
| */ | ||
| disconnectedCallback() { | ||
| this.destroy(); | ||
| } | ||
| /** | ||
| * Called when an observed attribute changes | ||
| */ | ||
| attributeChangedCallback(t, e, o) { | ||
| e !== o && (this.config = this.resolveConfig(), this.handleAttributeChange(t, o)); | ||
| } | ||
| /** | ||
| * Set configuration via JavaScript API | ||
| */ | ||
| setConfig(t) { | ||
| this.jsConfig = t, this.config = this.resolveConfig(), this.isConnected && (this.destroy(), this.initialize()); | ||
| } | ||
| /** | ||
| * Initialize the editor | ||
| */ | ||
| initialize() { | ||
| if (this.querySelector(".editora-toolbar") || this.isInitialized) return; | ||
| this.setAttribute("data-editora-editor", "true"), this.config.height && (this.style.height = typeof this.config.height == "number" ? `${this.config.height}px` : this.config.height), this.config.width && (this.style.width = typeof this.config.width == "number" ? `${this.config.width}px` : this.config.width), this.classList.add("editora-editor"), this.config.theme && this.classList.add(`editora-theme-${this.config.theme}`); | ||
| const t = this.loadPlugins(); | ||
| t.forEach((o) => { | ||
| if (o.init && typeof o.init == "function") | ||
| try { | ||
| o.init(); | ||
| } catch (i) { | ||
| console.error(`[RichTextEditor] Error initializing plugin ${o.name}:`, i); | ||
| } | ||
| }); | ||
| const e = this.getAttribute("data-initial-content") || ""; | ||
| this.engine = new k({ | ||
| content: e, | ||
| plugins: t, | ||
| readonly: this.config.readonly | ||
| }), this.createUI(t, e), this.setupEventListeners(), this.isInitialized = !0, this.dispatchEvent(new CustomEvent("editor-ready", { | ||
| detail: { api: this.getAPI() }, | ||
| bubbles: !0 | ||
| })); | ||
| } | ||
| /** | ||
| * Get initial content from slot or attribute | ||
| */ | ||
| getInitialContent() { | ||
| if (this.config.content) | ||
| return this.config.content; | ||
| const t = this.querySelector("[slot]"); | ||
| return t ? t.innerHTML : this.hasChildNodes() ? Array.from(this.childNodes).map((o) => o.nodeType === Node.TEXT_NODE ? o.textContent : o.nodeType === Node.ELEMENT_NODE ? o.outerHTML : "").join("").trim() : ""; | ||
| } | ||
| /** | ||
| * Load plugins based on configuration | ||
| */ | ||
| loadPlugins() { | ||
| const t = []; | ||
| if (this.config.plugins && (typeof this.config.plugins == "string" && this.config.plugins.length > 0 || Array.isArray(this.config.plugins) && this.config.plugins.length > 0)) | ||
| if (typeof this.config.plugins == "string") { | ||
| const o = this.pluginLoader.parsePluginString(this.config.plugins); | ||
| t.push(...o); | ||
| } else Array.isArray(this.config.plugins) && this.config.plugins.forEach((o) => { | ||
| if (typeof o == "string") { | ||
| const i = this.pluginLoader.load(o); | ||
| i && t.push(i); | ||
| } else | ||
| t.push(o); | ||
| }); | ||
| else { | ||
| const o = this.pluginLoader.getRegisteredPluginNames(), i = this.pluginLoader.loadMultiple(o); | ||
| t.push(...i); | ||
| } | ||
| return t; | ||
| } | ||
| /** | ||
| * Create UI elements | ||
| */ | ||
| createUI(t, e) { | ||
| const o = this.querySelector('[slot="toolbar"]'), i = this.querySelector('[slot="statusbar"]'); | ||
| if (this.innerHTML = "", this.config.toolbar !== !1 && !o) { | ||
| this.toolbarElement = document.createElement("div"), this.toolbarElement.className = "editora-toolbar-container", this.appendChild(this.toolbarElement); | ||
| const n = this.config.toolbarItems || this.config.toolbar; | ||
| this.toolbar = new v( | ||
| { | ||
| items: typeof n == "string" ? n : void 0, | ||
| sticky: this.config.toolbar && typeof this.config.toolbar == "object" ? this.config.toolbar.sticky : !1, | ||
| position: "top" | ||
| }, | ||
| t, | ||
| this.pluginLoader | ||
| // Pass plugin loader to get all registered plugins | ||
| ), this.toolbar.setCommandHandler((s, r) => { | ||
| var f, p; | ||
| if (this.contentElement) { | ||
| this.contentElement.focus(); | ||
| const c = window.getSelection(); | ||
| if (!c || c.rangeCount === 0 || !this.contentElement.contains(c.anchorNode)) { | ||
| const a = document.createRange(), l = this.contentElement.lastChild || this.contentElement; | ||
| l.nodeType === Node.TEXT_NODE ? a.setStart(l, ((f = l.textContent) == null ? void 0 : f.length) || 0) : l.nodeType === Node.ELEMENT_NODE ? (a.selectNodeContents(l), a.collapse(!1)) : a.setStart(this.contentElement, 0), a.collapse(!0), c == null || c.removeAllRanges(), c == null || c.addRange(a); | ||
| } | ||
| } | ||
| const d = t.find((c) => c.commands && c.commands[s]); | ||
| if (d && d.commands) { | ||
| const c = d.commands[s]; | ||
| if (typeof c == "function") | ||
| try { | ||
| return c(s === "toggleFullscreen" ? this : r); | ||
| } catch (a) { | ||
| return console.error(`[RichTextEditor] Error executing native command ${s}:`, a), !1; | ||
| } | ||
| } | ||
| return ((p = this.engine) == null ? void 0 : p.execCommand(s, r)) || !1; | ||
| }), this.toolbar.render(this.toolbarElement); | ||
| } else o && this.appendChild(o); | ||
| this.contentElement = document.createElement("div"), this.contentElement.className = "editora-content rte-content", this.contentElement.contentEditable = this.config.readonly ? "false" : "true", this.contentElement.setAttribute("role", "textbox"), this.contentElement.setAttribute("aria-multiline", "true"), this.config.placeholder && this.contentElement.setAttribute("data-placeholder", this.config.placeholder); | ||
| try { | ||
| document.execCommand("defaultParagraphSeparator", !1, "p"); | ||
| } catch (n) { | ||
| console.warn("defaultParagraphSeparator not supported:", n); | ||
| } | ||
| if (e) { | ||
| const n = document.createElement("div"); | ||
| n.innerHTML = e.trim(), !Array.from(n.childNodes).some((r) => { | ||
| if (r.nodeType === Node.ELEMENT_NODE) { | ||
| const d = r.tagName; | ||
| return ["P", "DIV", "H1", "H2", "H3", "H4", "H5", "H6", "UL", "OL", "BLOCKQUOTE", "PRE"].includes(d); | ||
| } | ||
| return !1; | ||
| }) && e.trim() ? this.contentElement.innerHTML = `<p>${e.trim()}</p>` : this.contentElement.innerHTML = e; | ||
| } else | ||
| this.config.placeholder ? this.contentElement.innerHTML = "" : this.contentElement.innerHTML = "<p><br></p>"; | ||
| this.appendChild(this.contentElement), this.config.toolbar && typeof this.config.toolbar == "object" && this.config.toolbar.floating && (this.floatingToolbar = new L({ enabled: !0 }), this.floatingToolbar.create(this)), i ? this.appendChild(i) : this.config.statusbar && (this.statusBarElement = document.createElement("div"), this.statusBarElement.className = "editora-statusbar-container", this.appendChild(this.statusBarElement), this.statusBar = new T({ position: "bottom" }), this.statusBar.create(this.statusBarElement)), this.config.autofocus && setTimeout(() => { | ||
| var n; | ||
| return (n = this.contentElement) == null ? void 0 : n.focus(); | ||
| }, 0); | ||
| } | ||
| /** | ||
| * Setup event listeners | ||
| */ | ||
| setupEventListeners() { | ||
| !this.contentElement || !this.engine || (this.contentElement.addEventListener("input", () => { | ||
| const t = this.contentElement.innerHTML; | ||
| if (this.dispatchEvent(new CustomEvent("content-change", { | ||
| detail: { html: t }, | ||
| bubbles: !0 | ||
| })), this.statusBar) { | ||
| const e = this.contentElement.textContent || "", o = e.trim().split(/\s+/).filter(Boolean).length, i = e.length; | ||
| this.statusBar.update({ wordCount: o, charCount: i }); | ||
| } | ||
| }), this.contentElement.addEventListener("focus", () => { | ||
| this.dispatchEvent(new Event("editor-focus", { bubbles: !0 })); | ||
| }), this.contentElement.addEventListener("blur", () => { | ||
| this.dispatchEvent(new Event("editor-blur", { bubbles: !0 })); | ||
| }), this.floatingToolbar && document.addEventListener("selectionchange", () => { | ||
| this.updateFloatingToolbar(); | ||
| })); | ||
| } | ||
| /** | ||
| * Update floating toolbar position | ||
| */ | ||
| updateFloatingToolbar() { | ||
| if (!this.floatingToolbar) return; | ||
| const t = window.getSelection(); | ||
| if (!t || t.rangeCount === 0) { | ||
| this.floatingToolbar.hide(); | ||
| return; | ||
| } | ||
| const e = t.getRangeAt(0); | ||
| if (e.collapsed) { | ||
| this.floatingToolbar.hide(); | ||
| return; | ||
| } | ||
| const o = e.getBoundingClientRect(); | ||
| this.floatingToolbar.show(o.left, o.top - 40); | ||
| } | ||
| /** | ||
| * Handle attribute changes | ||
| */ | ||
| handleAttributeChange(t, e) { | ||
| switch (t) { | ||
| case "readonly": | ||
| this.contentElement && (this.contentElement.contentEditable = e === "true" ? "false" : "true"), this.engine && this.engine.setReadonly(e === "true"); | ||
| break; | ||
| case "theme": | ||
| this.classList.forEach((o) => { | ||
| o.startsWith("editora-theme-") && this.classList.remove(o); | ||
| }), e && this.classList.add(`editora-theme-${e}`); | ||
| break; | ||
| case "placeholder": | ||
| this.contentElement && this.contentElement.setAttribute("data-placeholder", e); | ||
| break; | ||
| case "toolbar": | ||
| case "plugins": | ||
| this.isConnected && (this.destroy(), this.initialize()); | ||
| break; | ||
| } | ||
| } | ||
| /** | ||
| * Resolve configuration from all sources | ||
| */ | ||
| resolveConfig() { | ||
| const t = {}; | ||
| for (let e = 0; e < this.attributes.length; e++) { | ||
| const o = this.attributes[e]; | ||
| t[o.name] = o.value; | ||
| } | ||
| return b.resolve({ | ||
| jsConfig: this.jsConfig, | ||
| attributes: t | ||
| }); | ||
| } | ||
| /** | ||
| * Get public API | ||
| */ | ||
| getAPI() { | ||
| return { | ||
| getContent: () => { | ||
| var t; | ||
| return ((t = this.contentElement) == null ? void 0 : t.innerHTML) || ""; | ||
| }, | ||
| setContent: (t) => { | ||
| this.contentElement && (this.contentElement.innerHTML = t); | ||
| }, | ||
| execCommand: (t, e) => { | ||
| var o; | ||
| return ((o = this.engine) == null ? void 0 : o.execCommand(t, e)) || !1; | ||
| }, | ||
| focus: () => { | ||
| var t; | ||
| (t = this.contentElement) == null || t.focus(); | ||
| }, | ||
| blur: () => { | ||
| var t; | ||
| (t = this.contentElement) == null || t.blur(); | ||
| }, | ||
| destroy: () => { | ||
| this.destroy(); | ||
| }, | ||
| on: (t, e) => (this.addEventListener(t, e), () => this.removeEventListener(t, e)), | ||
| getConfig: () => ({ ...this.config }), | ||
| setReadonly: (t) => { | ||
| this.setAttribute("readonly", t.toString()); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Destroy the editor | ||
| */ | ||
| destroy() { | ||
| var t, e, o, i; | ||
| (t = this.engine) == null || t.destroy(), (e = this.toolbar) == null || e.destroy(), (o = this.floatingToolbar) == null || o.destroy(), (i = this.statusBar) == null || i.destroy(), this.innerHTML = "", this.isInitialized = !1, this.dispatchEvent(new Event("editor-destroy", { bubbles: !0 })); | ||
| } | ||
| // Public API methods | ||
| getContent() { | ||
| var t; | ||
| return ((t = this.contentElement) == null ? void 0 : t.innerHTML) || ""; | ||
| } | ||
| setContent(t) { | ||
| this.contentElement && (this.contentElement.innerHTML = t); | ||
| } | ||
| execCommand(t, e) { | ||
| var o; | ||
| return ((o = this.engine) == null ? void 0 : o.execCommand(t, e)) || !1; | ||
| } | ||
| focus() { | ||
| var t; | ||
| (t = this.contentElement) == null || t.focus(); | ||
| } | ||
| blur() { | ||
| var t; | ||
| (t = this.contentElement) == null || t.blur(); | ||
| } | ||
| } | ||
| export { | ||
| w as C, | ||
| m as E, | ||
| L as F, | ||
| C as P, | ||
| M as R, | ||
| E as S, | ||
| v as T, | ||
| k as a, | ||
| T as b, | ||
| b as c, | ||
| P as d, | ||
| N as i | ||
| }; | ||
| //# sourceMappingURL=index-BS4zT-KN.mjs.map |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BK2lHfHK.js");exports.RichTextEditorElement=e.RichTextEditorElement;exports.initWebComponent=e.initWebComponent; | ||
| //# sourceMappingURL=webcomponent.cjs.js.map |
| {"version":3,"file":"webcomponent.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":""} |
| import { R as i, i as o } from "./index-BS4zT-KN.mjs"; | ||
| export { | ||
| i as RichTextEditorElement, | ||
| o as initWebComponent | ||
| }; | ||
| //# sourceMappingURL=webcomponent.esm.js.map |
| {"version":3,"file":"webcomponent.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
+517
-4
@@ -1,7 +0,520 @@ | ||
| "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class c{constructor(e,t,i){this.doc=e,this.selection=t,this.schema=i}static create(e,t){const i=t||e.node("doc",{},[e.node("paragraph")]);return new c(i,{anchor:0,head:0},e)}apply(e,t){return new c(e,t||this.selection,this.schema)}}class f{constructor(e){this.listeners=[],this.pluginManager=e;const t=e.buildSchema();this.state=c.create(t),this.commands=e.getCommands()}setState(e){this.state=e,this.listeners.forEach(t=>t(e))}onChange(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}execCommand(e){const t=this.commands[e];if(!t)return!1;const i=t(this.state);return i?(this.setState(i),!0):!1}setContent(e){this.setState(this.state.apply(e))}getContent(){return this.state.doc}}class p{constructor(e,t){this.nodes=new Map(Object.entries(e)),this.marks=new Map(Object.entries(t))}node(e,t,i){return{type:e,attrs:t,content:i}}text(e,t){return{type:"text",text:e,marks:t}}}class y{constructor(){this.plugins=[]}register(e){this.plugins.push(e)}buildSchema(){const e={},t={};return this.plugins.forEach(i=>{i.nodes&&Object.assign(e,i.nodes),i.marks&&Object.assign(t,i.marks)}),new p(e,t)}getCommands(){const e={};return this.plugins.forEach(t=>{t.commands&&Object.assign(e,t.commands)}),e}getToolbarItems(){return this.plugins.flatMap(e=>e.toolbar||[])}}class g{constructor(e){this.initialized=!1,this.plugin=e}initialize(e){if(this.initialized)return console.warn(`Plugin "${this.plugin.name}" already initialized`),!1;try{return this.context=e,this.plugin.context?.initialize&&this.plugin.context.initialize(),this.plugin.context?.onEditorReady&&e.provider&&this.plugin.context.onEditorReady(e),this.initialized=!0,!0}catch(t){return console.error(`Failed to initialize plugin "${this.plugin.name}":`,t),!1}}destroy(){if(!this.initialized)return!1;try{return this.plugin.context?.destroy&&this.plugin.context.destroy(),this.initialized=!1,this.context=void 0,!0}catch(e){return console.error(`Failed to destroy plugin "${this.plugin.name}":`,e),!1}}executeCommand(e,...t){if(!this.initialized)return console.warn(`Plugin "${this.plugin.name}" not initialized, cannot execute command "${e}"`),null;try{const i=this.plugin.commands?.[e];return i?i(...t):(console.warn(`Command "${e}" not found in plugin "${this.plugin.name}"`),null)}catch(i){return console.error(`Error executing command "${e}" in plugin "${this.plugin.name}":`,i),null}}getName(){return this.plugin.name}isInitialized(){return this.initialized}getPlugin(){return this.plugin}getContext(){return this.context}}function S(n){return new g(n)}class k{constructor(e){this.shortcuts=new Map,this.enabled=!0,this.isMac=typeof navigator<"u"&&navigator.platform.toUpperCase().indexOf("MAC")>=0,e?.enabled===!1&&(this.enabled=!1),this.registerDefaultShortcuts(),e?.shortcuts&&e.shortcuts.forEach(t=>this.registerShortcut(t)),e?.customShortcuts&&Object.values(e.customShortcuts).forEach(t=>{this.registerShortcut(t)})}registerDefaultShortcuts(){this.registerShortcut({key:"b",ctrl:!this.isMac,meta:this.isMac,command:"toggleBold",description:"Bold",preventDefault:!0}),this.registerShortcut({key:"i",ctrl:!this.isMac,meta:this.isMac,command:"toggleItalic",description:"Italic",preventDefault:!0}),this.registerShortcut({key:"u",ctrl:!this.isMac,meta:this.isMac,command:"toggleUnderline",description:"Underline",preventDefault:!0}),this.registerShortcut({key:"d",ctrl:!this.isMac,meta:this.isMac,command:"toggleStrikethrough",description:"Strikethrough",preventDefault:!0}),this.registerShortcut({key:"z",ctrl:!this.isMac,meta:this.isMac,command:"undo",description:"Undo",preventDefault:!0}),this.registerShortcut({key:"z",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"redo",description:"Redo",preventDefault:!0}),this.registerShortcut({key:"y",ctrl:!this.isMac,meta:this.isMac,command:"redo",description:"Redo",preventDefault:!0});for(let e=1;e<=6;e++)this.registerShortcut({key:String(e),ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"setBlockType",params:`h${e}`,description:`Heading ${e}`,preventDefault:!0});this.registerShortcut({key:"7",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"setBlockType",params:"p",description:"Paragraph",preventDefault:!0}),this.registerShortcut({key:"7",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleOrderedList",description:"Numbered List",preventDefault:!0}),this.registerShortcut({key:"8",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleBulletList",description:"Bullet List",preventDefault:!0}),this.registerShortcut({key:"k",ctrl:!this.isMac,meta:this.isMac,command:"openLinkDialog",description:"Insert/Edit Link",preventDefault:!0}),this.registerShortcut({key:"e",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"insertCodeBlock",description:"Code Block",preventDefault:!0}),this.registerShortcut({key:"q",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleBlockquote",description:"Blockquote",preventDefault:!0}),this.registerShortcut({key:"l",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"setTextAlignment",params:"left",description:"Align Left",preventDefault:!0}),this.registerShortcut({key:"e",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"setTextAlignment",params:"center",description:"Align Center",preventDefault:!0}),this.registerShortcut({key:"r",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"setTextAlignment",params:"right",description:"Align Right",preventDefault:!0}),this.registerShortcut({key:"j",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"setTextAlignment",params:"justify",description:"Justify",preventDefault:!0}),this.registerShortcut({key:"\\",ctrl:!this.isMac,meta:this.isMac,command:"clearFormatting",description:"Clear Formatting",preventDefault:!0}),this.registerShortcut({key:"]",ctrl:!this.isMac,meta:this.isMac,command:"increaseIndent",description:"Indent",preventDefault:!0}),this.registerShortcut({key:"[",ctrl:!this.isMac,meta:this.isMac,command:"decreaseIndent",description:"Outdent",preventDefault:!0}),this.registerShortcut({key:"g",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"insertImage",description:"Insert Image",preventDefault:!0}),this.registerShortcut({key:"t",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"insertTable",description:"Insert Table",preventDefault:!0}),this.registerShortcut({key:"f11",command:"toggleFullscreen",description:"Toggle Fullscreen",preventDefault:!0}),this.registerShortcut({key:"p",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"togglePreview",description:"Preview",preventDefault:!0}),this.registerShortcut({key:"p",ctrl:!this.isMac,meta:this.isMac,command:"print",description:"Print",preventDefault:!0}),this.registerShortcut({key:"s",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"insertSpecialCharacter",description:"Insert Special Character",preventDefault:!0}),this.registerShortcut({key:"m",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"insertEmoji",description:"Insert Emoji",preventDefault:!0}),this.registerShortcut({key:"9",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleChecklist",description:"Checklist",preventDefault:!0}),this.registerShortcut({key:"a",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"toggleA11yChecker",description:"Accessibility Checker",preventDefault:!0}),this.registerShortcut({key:"F7",command:"toggleSpellCheck",description:"Spell Check",preventDefault:!0}),this.registerShortcut({key:"m",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"insertMath",description:"Insert Math",preventDefault:!0}),this.registerShortcut({key:"f",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"insertFootnote",description:"Insert Footnote",preventDefault:!0})}registerShortcut(e){const t=this.getShortcutKey(e);this.shortcuts.set(t,e)}unregisterShortcut(e){const t=this.getShortcutKey(e);this.shortcuts.delete(t)}getShortcutKey(e){const t=[];return e.ctrl&&t.push("ctrl"),e.alt&&t.push("alt"),e.shift&&t.push("shift"),e.meta&&t.push("meta"),t.push(e.key.toLowerCase()),t.join("+")}getEventKey(e){const t=[];return e.ctrlKey&&t.push("ctrl"),e.altKey&&t.push("alt"),e.shiftKey&&t.push("shift"),e.metaKey&&t.push("meta"),t.push(e.key.toLowerCase()),t.join("+")}handleKeyDown(e,t){if(!this.enabled)return!1;const i=this.getEventKey(e),r=this.shortcuts.get(i);return r?(r.preventDefault!==!1&&(e.preventDefault(),e.stopPropagation()),t(r.command,r.params),!0):!1}enable(){this.enabled=!0}disable(){this.enabled=!1}isEnabled(){return this.enabled}getAllShortcuts(){return Array.from(this.shortcuts.values())}getShortcutForCommand(e){return Array.from(this.shortcuts.values()).find(t=>t.command===e)}getShortcutDescription(e){const t=[];this.isMac?(e.meta&&t.push("⌘"),e.ctrl&&t.push("⌃"),e.alt&&t.push("⌥"),e.shift&&t.push("⇧")):(e.ctrl&&t.push("Ctrl"),e.alt&&t.push("Alt"),e.shift&&t.push("Shift"));const i=e.key.length===1?e.key.toUpperCase():e.key;return t.push(i),t.join("+")}getShortcutsHelp(){const e=this.getAllShortcuts(),t=new Map;e.forEach(r=>{const a=this.getShortcutCategory(r.command);t.has(a)||t.set(a,[]),t.get(a).push(r)});let i=`# Keyboard Shortcuts | ||
| "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./index-BK2lHfHK.js");class v{constructor(e){if(this.listeners=[],e instanceof l.PluginManager)this.pluginManager=e;else{const i=e;this.pluginManager=new l.PluginManager,i.plugins&&Array.isArray(i.plugins)&&i.plugins.forEach(n=>{this.pluginManager.register(n)}),i.element&&(this.domElement=i.element,this.setupDOMElement(i))}const t=this.pluginManager.buildSchema();this.state=l.EditorState.create(t),this.commands=this.pluginManager.getCommands()}setupDOMElement(e){this.domElement&&(e.enableToolbar!==!1&&e.toolbarElement?this.toolbarElement=e.toolbarElement:e.enableToolbar!==!1&&(this.toolbarElement=document.createElement("div"),this.toolbarElement.className="editora-toolbar-container",this.domElement.appendChild(this.toolbarElement)),this.contentElement=document.createElement("div"),this.contentElement.contentEditable="true",this.contentElement.className="editora-content",this.contentElement.style.minHeight="200px",this.contentElement.style.outline="none",this.contentElement.style.padding="12px",e.content&&(this.contentElement.innerHTML=e.content),this.domElement.appendChild(this.contentElement),this.contentElement.addEventListener("input",()=>{this.listeners.forEach(t=>t(this.state))}))}setupKeyboardShortcuts(e){const t={};e.forEach(i=>{i.shortcut&&(t[i.shortcut.toLowerCase()]=i.command)}),document.addEventListener("keydown",i=>{if(this.contentElement!==document.activeElement&&!(document.activeElement instanceof HTMLElement&&document.activeElement.contentEditable==="true"))return;const n=[];(i.ctrlKey||i.metaKey)&&n.push("ctrl"),i.shiftKey&&n.push("shift"),i.altKey&&n.push("alt");const s=i.key.toLowerCase(),o=n.length>0?`${n.join("+")}+${s}`:s,r=t[o];r&&(i.preventDefault(),this.execCommand(r))})}handleToolbarCommand(e,t){const n=this.pluginManager.getToolbarItems().find(s=>s.id&&s.id===e||s.command===e);n&&(t!==void 0?this.execCommand(n.command,t):this.execCommand(n.command))}setState(e){this.state=e,this.listeners.forEach(t=>t(e))}onChange(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}on(e,t){return e==="change"||e==="input"?this.onChange(t):()=>{}}getElement(){return this.contentElement||this.domElement||null}execCommand(e,t){const i=this.commands[e];if(!i)return console.warn(`Command not found: ${e}`),!1;let n;return t!==void 0?n=i(this.state,t):n=i(this.state),n?(this.setState(n),!0):!1}setContent(e){typeof e=="string"?this.contentElement&&(this.contentElement.innerHTML=e):this.setState(this.state.apply(e))}getContent(){return this.contentElement?this.contentElement.innerHTML:this.state.doc}destroy(){this.listeners=[],this.contentElement&&this.contentElement.removeEventListener("input",()=>{})}}class f{constructor(e){this.initialized=!1,this.plugin=e}initialize(e){var t,i;if(this.initialized)return console.warn(`Plugin "${this.plugin.name}" already initialized`),!1;try{return this.context=e,(t=this.plugin.context)!=null&&t.initialize&&this.plugin.context.initialize(),(i=this.plugin.context)!=null&&i.onEditorReady&&e.provider&&this.plugin.context.onEditorReady(e),this.initialized=!0,!0}catch(n){return console.error(`Failed to initialize plugin "${this.plugin.name}":`,n),!1}}destroy(){var e;if(!this.initialized)return!1;try{return(e=this.plugin.context)!=null&&e.destroy&&this.plugin.context.destroy(),this.initialized=!1,this.context=void 0,!0}catch(t){return console.error(`Failed to destroy plugin "${this.plugin.name}":`,t),!1}}executeCommand(e,...t){var i;if(!this.initialized)return console.warn(`Plugin "${this.plugin.name}" not initialized, cannot execute command "${e}"`),null;try{const n=(i=this.plugin.commands)==null?void 0:i[e];return n?n(...t):(console.warn(`Command "${e}" not found in plugin "${this.plugin.name}"`),null)}catch(n){return console.error(`Error executing command "${e}" in plugin "${this.plugin.name}":`,n),null}}getName(){return this.plugin.name}isInitialized(){return this.initialized}getPlugin(){return this.plugin}getContext(){return this.context}}function E(a){return new f(a)}class S{constructor(e){this.shortcuts=new Map,this.enabled=!0,this.isMac=typeof navigator!="undefined"&&navigator.platform.toUpperCase().indexOf("MAC")>=0,(e==null?void 0:e.enabled)===!1&&(this.enabled=!1),this.registerDefaultShortcuts(),e!=null&&e.shortcuts&&e.shortcuts.forEach(t=>this.registerShortcut(t)),e!=null&&e.customShortcuts&&Object.values(e.customShortcuts).forEach(t=>{this.registerShortcut(t)})}registerDefaultShortcuts(){this.registerShortcut({key:"b",ctrl:!this.isMac,meta:this.isMac,command:"toggleBold",description:"Bold",preventDefault:!0}),this.registerShortcut({key:"i",ctrl:!this.isMac,meta:this.isMac,command:"toggleItalic",description:"Italic",preventDefault:!0}),this.registerShortcut({key:"u",ctrl:!this.isMac,meta:this.isMac,command:"toggleUnderline",description:"Underline",preventDefault:!0}),this.registerShortcut({key:"d",ctrl:!this.isMac,meta:this.isMac,command:"toggleStrikethrough",description:"Strikethrough",preventDefault:!0}),this.registerShortcut({key:"z",ctrl:!this.isMac,meta:this.isMac,command:"undo",description:"Undo",preventDefault:!0}),this.registerShortcut({key:"z",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"redo",description:"Redo",preventDefault:!0}),this.registerShortcut({key:"y",ctrl:!this.isMac,meta:this.isMac,command:"redo",description:"Redo",preventDefault:!0});for(let e=1;e<=6;e++)this.registerShortcut({key:String(e),ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"setBlockType",params:`h${e}`,description:`Heading ${e}`,preventDefault:!0});this.registerShortcut({key:"7",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"setBlockType",params:"p",description:"Paragraph",preventDefault:!0}),this.registerShortcut({key:"7",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleOrderedList",description:"Numbered List",preventDefault:!0}),this.registerShortcut({key:"8",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleBulletList",description:"Bullet List",preventDefault:!0}),this.registerShortcut({key:"k",ctrl:!this.isMac,meta:this.isMac,command:"openLinkDialog",description:"Insert/Edit Link",preventDefault:!0}),this.registerShortcut({key:"e",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"insertCodeBlock",description:"Code Block",preventDefault:!0}),this.registerShortcut({key:"q",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleBlockquote",description:"Blockquote",preventDefault:!0}),this.registerShortcut({key:"l",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"setTextAlignment",params:"left",description:"Align Left",preventDefault:!0}),this.registerShortcut({key:"e",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"setTextAlignment",params:"center",description:"Align Center",preventDefault:!0}),this.registerShortcut({key:"r",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"setTextAlignment",params:"right",description:"Align Right",preventDefault:!0}),this.registerShortcut({key:"j",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"setTextAlignment",params:"justify",description:"Justify",preventDefault:!0}),this.registerShortcut({key:"\\",ctrl:!this.isMac,meta:this.isMac,command:"clearFormatting",description:"Clear Formatting",preventDefault:!0}),this.registerShortcut({key:"]",ctrl:!this.isMac,meta:this.isMac,command:"increaseIndent",description:"Indent",preventDefault:!0}),this.registerShortcut({key:"[",ctrl:!this.isMac,meta:this.isMac,command:"decreaseIndent",description:"Outdent",preventDefault:!0}),this.registerShortcut({key:"g",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"insertImage",description:"Insert Image",preventDefault:!0}),this.registerShortcut({key:"t",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"insertTable",description:"Insert Table",preventDefault:!0}),this.registerShortcut({key:"f11",command:"toggleFullscreen",description:"Toggle Fullscreen",preventDefault:!0}),this.registerShortcut({key:"p",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"togglePreview",description:"Preview",preventDefault:!0}),this.registerShortcut({key:"p",ctrl:!this.isMac,meta:this.isMac,command:"print",description:"Print",preventDefault:!0}),this.registerShortcut({key:"s",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"insertSpecialCharacter",description:"Insert Special Character",preventDefault:!0}),this.registerShortcut({key:"m",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"insertEmoji",description:"Insert Emoji",preventDefault:!0}),this.registerShortcut({key:"9",ctrl:!this.isMac,meta:this.isMac,shift:!0,command:"toggleChecklist",description:"Checklist",preventDefault:!0}),this.registerShortcut({key:"a",ctrl:!this.isMac,meta:this.isMac,shift:!0,alt:!0,command:"toggleA11yChecker",description:"Accessibility Checker",preventDefault:!0}),this.registerShortcut({key:"F7",command:"toggleSpellCheck",description:"Spell Check",preventDefault:!0}),this.registerShortcut({key:"m",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"insertMath",description:"Insert Math",preventDefault:!0}),this.registerShortcut({key:"f",ctrl:!this.isMac,meta:this.isMac,alt:!0,command:"insertFootnote",description:"Insert Footnote",preventDefault:!0})}registerShortcut(e){const t=this.getShortcutKey(e);this.shortcuts.set(t,e)}unregisterShortcut(e){const t=this.getShortcutKey(e);this.shortcuts.delete(t)}getShortcutKey(e){const t=[];return e.ctrl&&t.push("ctrl"),e.alt&&t.push("alt"),e.shift&&t.push("shift"),e.meta&&t.push("meta"),t.push(e.key.toLowerCase()),t.join("+")}getEventKey(e){const t=[];return e.ctrlKey&&t.push("ctrl"),e.altKey&&t.push("alt"),e.shiftKey&&t.push("shift"),e.metaKey&&t.push("meta"),t.push(e.key.toLowerCase()),t.join("+")}handleKeyDown(e,t){if(!this.enabled)return!1;const i=this.getEventKey(e),n=this.shortcuts.get(i);return n?(n.preventDefault!==!1&&(e.preventDefault(),e.stopPropagation()),t(n.command,n.params),!0):!1}enable(){this.enabled=!0}disable(){this.enabled=!1}isEnabled(){return this.enabled}getAllShortcuts(){return Array.from(this.shortcuts.values())}getShortcutForCommand(e){return Array.from(this.shortcuts.values()).find(t=>t.command===e)}getShortcutDescription(e){const t=[];this.isMac?(e.meta&&t.push("⌘"),e.ctrl&&t.push("⌃"),e.alt&&t.push("⌥"),e.shift&&t.push("⇧")):(e.ctrl&&t.push("Ctrl"),e.alt&&t.push("Alt"),e.shift&&t.push("Shift"));const i=e.key.length===1?e.key.toUpperCase():e.key;return t.push(i),t.join("+")}getShortcutsHelp(){const e=this.getAllShortcuts(),t=new Map;e.forEach(n=>{const s=this.getShortcutCategory(n.command);t.has(s)||t.set(s,[]),t.get(s).push(n)});let i=`# Keyboard Shortcuts | ||
| `;return t.forEach((r,a)=>{i+=`## ${a} | ||
| `;return t.forEach((n,s)=>{i+=`## ${s} | ||
| `,r.forEach(l=>{const o=this.getShortcutDescription(l);i+=`- **${o}**: ${l.description||l.command} | ||
| `,n.forEach(o=>{const r=this.getShortcutDescription(o);i+=`- **${r}**: ${o.description||o.command} | ||
| `}),i+=` | ||
| `}),i}getShortcutCategory(e){return e.includes("toggle")&&(e.includes("Bold")||e.includes("Italic")||e.includes("Underline")||e.includes("Strike")||e.includes("Code")||e.includes("Super")||e.includes("Sub"))?"Text Formatting":e.includes("Heading")||e.includes("Paragraph")?"Block Formatting":e.includes("List")||e.includes("Checklist")?"Lists":e.includes("Alignment")||e.includes("Indent")?"Alignment & Indentation":e.includes("undo")||e.includes("redo")?"History":e.includes("insert")?"Insert":e.includes("find")||e.includes("replace")?"Find & Replace":e.includes("Accessibility")||e.includes("spell")?"Tools":"Other"}}function M(n={}){const{enabled:e=!1,provider:t="browser",apiUrl:i="",apiHeaders:r={},language:a="en",customDictionary:l=[],ignoreAllCaps:o=!0,ignoreNumbers:m=!0}=n;return{name:"spellcheck",context:{initialize:()=>{if(e)switch(console.log("[Spellcheck Plugin] Initialized",{provider:t,language:a}),t){case"browser":console.log("[Spellcheck] Using browser spellcheck");break;case"local":console.log("[Spellcheck] Using local dictionary (not implemented)");break;case"api":i?console.log("[Spellcheck] Using API:",i):console.warn("[Spellcheck] API provider selected but no apiUrl provided");break}},destroy:()=>{console.log("[Spellcheck Plugin] Destroyed")},onEditorReady:u=>{console.log("[Spellcheck Plugin] Editor ready")}},commands:{toggleSpellcheck:()=>(console.log("[Spellcheck] Toggle command (not implemented)"),null),addToDictionary:u=>(console.log("[Spellcheck] Add to dictionary:",u),null),checkSpelling:async()=>(console.log("[Spellcheck] Check spelling (not implemented)"),null)},toolbar:e?[{label:"Spellcheck",command:"toggleSpellcheck",icon:"Aa",type:"button"}]:[]}}function b(n={}){const{uploadUrl:e="",libraryUrl:t="",maxFileSize:i=10*1024*1024,allowedTypes:r=["image/jpeg","image/png","image/gif","image/webp"],headers:a={},withCredentials:l=!1,chunkSize:o=1024*1024,enableChunking:m=!0,onProgress:u,onError:d,onSuccess:v}=n;return{name:"media",context:{initialize:()=>{console.log("[Media Plugin] Initialized",{uploadUrl:e,libraryUrl:t,maxFileSize:i,allowedTypes:r}),e||console.warn("[Media] No uploadUrl provided - upload will not work")},destroy:()=>{console.log("[Media Plugin] Destroyed")},onEditorReady:s=>{console.log("[Media Plugin] Editor ready")}},commands:{insertImage:async s=>{if(console.log("[Media] Insert image command (not implemented)",s),!s)return console.log("[Media] No file provided - should open picker"),null;if(!r.includes(s.type)){const h=new Error(`File type ${s.type} not allowed`);return d?.(h),null}if(s.size>i){const h=new Error(`File size ${s.size} exceeds max ${i}`);return d?.(h),null}return null},openMediaLibrary:()=>(console.log("[Media] Open media library (not implemented)"),t||console.warn("[Media] No libraryUrl provided"),null),uploadMedia:async s=>(console.log("[Media] Upload media (not implemented)",{name:s.name,size:s.size,type:s.type}),null)},toolbar:[{label:"Image",command:"insertImage",icon:"🖼️",type:"button"},{label:"Media Library",command:"openMediaLibrary",icon:"📁",type:"button"}]}}exports.Editor=f;exports.EditorState=c;exports.KeyboardShortcutManager=k;exports.PluginManager=y;exports.PluginRuntime=g;exports.Schema=p;exports.createMediaPlugin=b;exports.createPluginRuntime=S;exports.createSpellcheckPlugin=M; | ||
| `}),i}getShortcutCategory(e){return e.includes("toggle")&&(e.includes("Bold")||e.includes("Italic")||e.includes("Underline")||e.includes("Strike")||e.includes("Code")||e.includes("Super")||e.includes("Sub"))?"Text Formatting":e.includes("Heading")||e.includes("Paragraph")?"Block Formatting":e.includes("List")||e.includes("Checklist")?"Lists":e.includes("Alignment")||e.includes("Indent")?"Alignment & Indentation":e.includes("undo")||e.includes("redo")?"History":e.includes("insert")?"Insert":e.includes("find")||e.includes("replace")?"Find & Replace":e.includes("Accessibility")||e.includes("spell")?"Tools":"Other"}}function w(a={}){const{enabled:e=!1,provider:t="browser",apiUrl:i="",apiHeaders:n={},language:s="en",customDictionary:o=[],ignoreAllCaps:r=!0,ignoreNumbers:c=!0}=a;return{name:"spellcheck",context:{initialize:()=>{if(e)switch(console.log("[Spellcheck Plugin] Initialized",{provider:t,language:s}),t){case"browser":console.log("[Spellcheck] Using browser spellcheck");break;case"local":console.log("[Spellcheck] Using local dictionary (not implemented)");break;case"api":i?console.log("[Spellcheck] Using API:",i):console.warn("[Spellcheck] API provider selected but no apiUrl provided");break}},destroy:()=>{console.log("[Spellcheck Plugin] Destroyed")},onEditorReady:h=>{console.log("[Spellcheck Plugin] Editor ready")}},commands:{toggleSpellcheck:()=>(console.log("[Spellcheck] Toggle command (not implemented)"),null),addToDictionary:h=>(console.log("[Spellcheck] Add to dictionary:",h),null),checkSpelling:async()=>(console.log("[Spellcheck] Check spelling (not implemented)"),null)},toolbar:e?[{label:"Spellcheck",command:"toggleSpellcheck",icon:"Aa",type:"button"}]:[]}}function x(a={}){const{uploadUrl:e="",libraryUrl:t="",maxFileSize:i=10*1024*1024,allowedTypes:n=["image/jpeg","image/png","image/gif","image/webp"],headers:s={},withCredentials:o=!1,chunkSize:r=1024*1024,enableChunking:c=!0,onProgress:h,onError:u,onSuccess:A}=a;return{name:"media",context:{initialize:()=>{console.log("[Media Plugin] Initialized",{uploadUrl:e,libraryUrl:t,maxFileSize:i,allowedTypes:n}),e||console.warn("[Media] No uploadUrl provided - upload will not work")},destroy:()=>{console.log("[Media Plugin] Destroyed")},onEditorReady:d=>{console.log("[Media Plugin] Editor ready")}},commands:{insertImage:async d=>{if(console.log("[Media] Insert image command (not implemented)",d),!d)return console.log("[Media] No file provided - should open picker"),null;if(!n.includes(d.type)){const g=new Error(`File type ${d.type} not allowed`);return u==null||u(g),null}if(d.size>i){const g=new Error(`File size ${d.size} exceeds max ${i}`);return u==null||u(g),null}return null},openMediaLibrary:()=>(console.log("[Media] Open media library (not implemented)"),t||console.warn("[Media] No libraryUrl provided"),null),uploadMedia:async d=>(console.log("[Media] Upload media (not implemented)",{name:d.name,size:d.size,type:d.type}),null)},toolbar:[{label:"Image",command:"insertImage",icon:"🖼️",type:"button"},{label:"Media Library",command:"openMediaLibrary",icon:"📁",type:"button"}]}}class p{constructor(e,t={anchor:0,head:0}){this.doc=e,this.selection=t}getDocument(){return this.doc}setDocument(e){return new p(e,this.selection)}getSelection(){return{...this.selection}}setSelection(e){return new p(this.doc,e)}update(e,t){return new p(e||this.doc,t||this.selection)}getTextContent(){return""}isSelectionEmpty(){return this.selection.anchor===this.selection.head}}class m{constructor(e){this.config={closeOnEscape:!0,closeOnBackdrop:!0,...e},this.element=this.createElement(),this.attachEventListeners()}createElement(){const e=document.createElement("dialog");if(e.className="editora-dialog",this.config.width&&(e.style.width=this.config.width),this.config.height&&(e.style.height=this.config.height),e.innerHTML=` | ||
| <div class="editora-dialog-container"> | ||
| <div class="editora-dialog-header"> | ||
| <h3>${this.config.title}</h3> | ||
| <button class="editora-dialog-close" aria-label="Close">×</button> | ||
| </div> | ||
| <div class="editora-dialog-body"> | ||
| ${typeof this.config.content=="string"?this.config.content:""} | ||
| </div> | ||
| <div class="editora-dialog-footer"> | ||
| <button type="button" class="editora-btn editora-btn-cancel">Cancel</button> | ||
| <button type="button" class="editora-btn editora-btn-primary">OK</button> | ||
| </div> | ||
| </div> | ||
| `,typeof this.config.content!="string"){const t=e.querySelector(".editora-dialog-body");t&&(t.innerHTML="",t.appendChild(this.config.content))}return e}attachEventListeners(){const e=this.element.querySelector(".editora-dialog-close");e==null||e.addEventListener("click",()=>this.close());const t=this.element.querySelector(".editora-btn-cancel");t==null||t.addEventListener("click",()=>{var n,s;(s=(n=this.config).onCancel)==null||s.call(n),this.close()});const i=this.element.querySelector(".editora-btn-primary");i==null||i.addEventListener("click",()=>this.handleSubmit()),this.config.closeOnEscape&&this.element.addEventListener("cancel",n=>{n.preventDefault(),this.close()}),this.config.closeOnBackdrop&&this.element.addEventListener("click",n=>{const s=this.element.getBoundingClientRect();(n.clientX<s.left||n.clientX>s.right||n.clientY<s.top||n.clientY>s.bottom)&&this.close()})}handleSubmit(){var t,i,n,s;const e=this.element.querySelector("form");if(e){const o=new FormData(e);(i=(t=this.config).onSubmit)==null||i.call(t,o)}else{const o=this.element.querySelectorAll("input, select, textarea"),r=new FormData;o.forEach(c=>{c.name&&r.append(c.name,c.value)}),(s=(n=this.config).onSubmit)==null||s.call(n,r)}this.close()}show(){document.body.appendChild(this.element),this.element.showModal()}close(){this.element.close(),this.element.remove()}destroy(){this.close()}}class C{constructor(e){this.isOpen=!1,this.config=e,this.selectedValue=e.value,this.element=this.createElement(),this.attachEventListeners()}createElement(){const e=document.createElement("div");e.className="editora-dropdown",this.config.width&&(e.style.width=this.config.width);const t=this.config.options.find(n=>n.value===this.selectedValue),i=(t==null?void 0:t.label)||this.config.placeholder||"Select...";return e.innerHTML=` | ||
| <button class="editora-dropdown-toggle" type="button"> | ||
| <span class="editora-dropdown-label">${i}</span> | ||
| <span class="editora-dropdown-arrow">▼</span> | ||
| </button> | ||
| <div class="editora-dropdown-menu" style="display: none;"> | ||
| ${this.config.options.map(n=>` | ||
| <div class="editora-dropdown-item" data-value="${n.value}"> | ||
| ${n.icon?`<span class="editora-dropdown-icon">${n.icon}</span>`:""} | ||
| <span>${n.label}</span> | ||
| </div> | ||
| `).join("")} | ||
| </div> | ||
| `,e}attachEventListeners(){const e=this.element.querySelector(".editora-dropdown-toggle"),t=this.element.querySelector(".editora-dropdown-menu");e.addEventListener("click",n=>{n.stopPropagation(),this.isOpen=!this.isOpen,t.style.display=this.isOpen?"block":"none"}),this.element.querySelectorAll(".editora-dropdown-item").forEach(n=>{n.addEventListener("click",()=>{var o,r;const s=n.getAttribute("data-value");s&&(this.setValue(s),(r=(o=this.config).onChange)==null||r.call(o,s),this.close())})}),document.addEventListener("click",n=>{this.element.contains(n.target)||this.close()})}setValue(e){this.selectedValue=e;const t=this.config.options.find(n=>n.value===e),i=this.element.querySelector(".editora-dropdown-label");i&&t&&(i.textContent=t.label)}getValue(){return this.selectedValue}close(){this.isOpen=!1;const e=this.element.querySelector(".editora-dropdown-menu");e&&(e.style.display="none")}getElement(){return this.element}destroy(){this.element.remove()}}class k{constructor(e){this.defaultPresets=["#000000","#434343","#666666","#999999","#B7B7B7","#CCCCCC","#D9D9D9","#EFEFEF","#F3F3F3","#FFFFFF","#980000","#FF0000","#FF9900","#FFFF00","#00FF00","#00FFFF","#4A86E8","#0000FF","#9900FF","#FF00FF","#E6B8AF","#F4CCCC","#FCE5CD","#FFF2CC","#D9EAD3","#D0E0E3","#C9DAF8","#CFE2F3","#D9D2E9","#EAD1DC"],this.config={presetColors:this.defaultPresets,...e},this.selectedColor=e.value,this.element=this.createElement(),this.attachEventListeners()}createElement(){var t;const e=document.createElement("div");return e.className="editora-color-picker",e.innerHTML=` | ||
| <div class="editora-color-picker-input"> | ||
| <input type="color" value="${this.selectedColor||"#000000"}" /> | ||
| <input type="text" value="${this.selectedColor||"#000000"}" placeholder="#000000" /> | ||
| </div> | ||
| <div class="editora-color-picker-presets"> | ||
| ${(t=this.config.presetColors)==null?void 0:t.map(i=>` | ||
| <button | ||
| class="editora-color-preset" | ||
| style="background-color: ${i};" | ||
| data-color="${i}" | ||
| title="${i}" | ||
| ></button> | ||
| `).join("")} | ||
| </div> | ||
| `,e}attachEventListeners(){const e=this.element.querySelector('input[type="color"]'),t=this.element.querySelector('input[type="text"]');e.addEventListener("input",n=>{var o,r;const s=n.target.value;t.value=s,this.selectedColor=s,(r=(o=this.config).onChange)==null||r.call(o,s)}),t.addEventListener("input",n=>{var o,r;const s=n.target.value;/^#[0-9A-Fa-f]{6}$/.test(s)&&(e.value=s,this.selectedColor=s,(r=(o=this.config).onChange)==null||r.call(o,s))}),this.element.querySelectorAll(".editora-color-preset").forEach(n=>{n.addEventListener("click",()=>{var o,r;const s=n.getAttribute("data-color");s&&(e.value=s,t.value=s,this.selectedColor=s,(r=(o=this.config).onChange)==null||r.call(o,s))})})}getValue(){return this.selectedColor}setValue(e){this.selectedColor=e;const t=this.element.querySelector('input[type="color"]'),i=this.element.querySelector('input[type="text"]');t&&(t.value=e),i&&(i.value=e)}getElement(){return this.element}destroy(){this.element.remove()}}class M{constructor(e){const{initialUrl:t="",initialText:i="",onSubmit:n,onCancel:s}=e;this.dialog=new m({title:"Insert/Edit Link",content:this.createFormHTML(t,i),onSubmit:o=>{const r=(o.get("url")||"").trim(),c=(o.get("text")||"").trim(),h=o.get("openInNewTab")==="on";if(!r){alert("Please enter a URL");return}n({url:r,text:c,openInNewTab:h}),this.dialog.close()},onCancel:()=>{s==null||s(),this.dialog.close()},width:"500px"})}createFormHTML(e,t){return` | ||
| <form class="link-dialog-form"> | ||
| <div class="form-group"> | ||
| <label for="link-url">URL</label> | ||
| <input | ||
| type="url" | ||
| id="link-url" | ||
| name="url" | ||
| placeholder="https://example.com" | ||
| value="${this.escapeHtml(e)}" | ||
| required | ||
| autofocus | ||
| /> | ||
| <small>Enter the web address (URL) for the link</small> | ||
| </div> | ||
| <div class="form-group"> | ||
| <label for="link-text">Link Text</label> | ||
| <input | ||
| type="text" | ||
| id="link-text" | ||
| name="text" | ||
| placeholder="Click here" | ||
| value="${this.escapeHtml(t)}" | ||
| /> | ||
| <small>Text to display for the link (leave empty to use URL)</small> | ||
| </div> | ||
| <div class="form-group"> | ||
| <label class="checkbox-label"> | ||
| <input | ||
| type="checkbox" | ||
| name="openInNewTab" | ||
| id="link-new-tab" | ||
| /> | ||
| <span>Open link in new tab</span> | ||
| </label> | ||
| </div> | ||
| <div class="form-actions"> | ||
| <button type="button" class="btn btn-secondary" data-action="cancel"> | ||
| Cancel | ||
| </button> | ||
| <button type="submit" class="btn btn-primary"> | ||
| Insert Link | ||
| </button> | ||
| </div> | ||
| </form> | ||
| `}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}show(){this.dialog.show()}close(){this.dialog.close()}}class L{constructor(e){const{onSubmit:t,onCancel:i}=e;this.dialog=new m({title:"Insert Table",content:this.createFormHTML(),onSubmit:n=>{const s=parseInt(n.get("rows"),10),o=parseInt(n.get("cols"),10),r=n.get("headerRow")==="on";if(s<1||s>100){alert("Please enter a valid number of rows (1-100)");return}if(o<1||o>20){alert("Please enter a valid number of columns (1-20)");return}t({rows:s,cols:o,headerRow:r}),this.dialog.close()},onCancel:()=>{i==null||i(),this.dialog.close()},width:"400px"})}createFormHTML(){return` | ||
| <form class="table-dialog-form"> | ||
| <div class="form-group"> | ||
| <label for="table-rows">Rows</label> | ||
| <input | ||
| type="number" | ||
| id="table-rows" | ||
| name="rows" | ||
| min="1" | ||
| max="100" | ||
| value="3" | ||
| required | ||
| autofocus | ||
| /> | ||
| <small>Number of rows (1-100)</small> | ||
| </div> | ||
| <div class="form-group"> | ||
| <label for="table-cols">Columns</label> | ||
| <input | ||
| type="number" | ||
| id="table-cols" | ||
| name="cols" | ||
| min="1" | ||
| max="20" | ||
| value="3" | ||
| required | ||
| /> | ||
| <small>Number of columns (1-20)</small> | ||
| </div> | ||
| <div class="form-group"> | ||
| <label class="checkbox-label"> | ||
| <input | ||
| type="checkbox" | ||
| name="headerRow" | ||
| id="table-header" | ||
| checked | ||
| /> | ||
| <span>Include header row</span> | ||
| </label> | ||
| </div> | ||
| <div class="table-preview"> | ||
| <strong>Preview:</strong> | ||
| <div id="table-preview-content" style="margin-top: 8px; font-size: 12px; color: #666;"> | ||
| 3 rows × 3 columns with header | ||
| </div> | ||
| </div> | ||
| <div class="form-actions"> | ||
| <button type="button" class="btn btn-secondary" data-action="cancel"> | ||
| Cancel | ||
| </button> | ||
| <button type="submit" class="btn btn-primary"> | ||
| Insert Table | ||
| </button> | ||
| </div> | ||
| </form> | ||
| `}show(){this.dialog.show(),this.attachPreviewListeners()}close(){this.dialog.close()}attachPreviewListeners(){const e=document.querySelector(".table-dialog-form");if(!e)return;const t=e.querySelector("#table-rows"),i=e.querySelector("#table-cols"),n=e.querySelector("#table-header"),s=e.querySelector("#table-preview-content"),o=()=>{const r=parseInt((t==null?void 0:t.value)||"3",10),c=parseInt((i==null?void 0:i.value)||"3",10),h=n==null?void 0:n.checked;s&&(s.textContent=`${r} rows × ${c} columns${h?" with header":""}`)};t==null||t.addEventListener("input",o),i==null||i.addEventListener("input",o),n==null||n.addEventListener("change",o)}}class T{constructor(e){this.config=e;const{onSubmit:t,onCancel:i}=e;this.dialog=new m({title:"Insert Image",content:this.createFormHTML(),onSubmit:n=>{const s=(n.get("src")||"").trim(),o=(n.get("alt")||"").trim(),r=(n.get("width")||"").trim(),c=(n.get("height")||"").trim();if(!s){alert("Please enter an image URL or upload an image");return}t({src:s,alt:o,width:r||void 0,height:c||void 0}),this.dialog.close()},onCancel:()=>{i==null||i(),this.dialog.close()},width:"500px"})}createFormHTML(){return` | ||
| <form class="image-dialog-form"> | ||
| ${this.config.allowUpload?` | ||
| <div class="form-group"> | ||
| <label for="image-upload">Upload Image</label> | ||
| <input | ||
| type="file" | ||
| id="image-upload" | ||
| accept="image/*" | ||
| /> | ||
| <small>Or upload an image from your computer</small> | ||
| </div> | ||
| <div class="form-divider">OR</div> | ||
| `:""} | ||
| <div class="form-group"> | ||
| <label for="image-src">Image URL</label> | ||
| <input | ||
| type="url" | ||
| id="image-src" | ||
| name="src" | ||
| placeholder="https://example.com/image.jpg" | ||
| ${this.config.allowUpload?"":"required autofocus"} | ||
| /> | ||
| <small>Enter the web address (URL) of the image</small> | ||
| </div> | ||
| <div class="form-group"> | ||
| <label for="image-alt">Alt Text</label> | ||
| <input | ||
| type="text" | ||
| id="image-alt" | ||
| name="alt" | ||
| placeholder="Description of the image" | ||
| /> | ||
| <small>Alternative text for accessibility (recommended)</small> | ||
| </div> | ||
| <div class="form-row"> | ||
| <div class="form-group"> | ||
| <label for="image-width">Width</label> | ||
| <input | ||
| type="text" | ||
| id="image-width" | ||
| name="width" | ||
| placeholder="auto" | ||
| /> | ||
| </div> | ||
| <div class="form-group"> | ||
| <label for="image-height">Height</label> | ||
| <input | ||
| type="text" | ||
| id="image-height" | ||
| name="height" | ||
| placeholder="auto" | ||
| /> | ||
| </div> | ||
| </div> | ||
| <div class="image-preview" id="image-preview" style="display: none;"> | ||
| <strong>Preview:</strong> | ||
| <img id="preview-img" style="max-width: 100%; max-height: 200px; margin-top: 8px;" /> | ||
| </div> | ||
| <div class="form-actions"> | ||
| <button type="button" class="btn btn-secondary" data-action="cancel"> | ||
| Cancel | ||
| </button> | ||
| <button type="submit" class="btn btn-primary"> | ||
| Insert Image | ||
| </button> | ||
| </div> | ||
| </form> | ||
| `}show(){this.dialog.show(),this.attachImagePreview(),this.attachFileUpload()}close(){this.dialog.close()}attachImagePreview(){const e=document.querySelector(".image-dialog-form");if(!e)return;const t=e.querySelector("#image-src"),i=e.querySelector("#image-preview"),n=e.querySelector("#preview-img");t==null||t.addEventListener("input",()=>{const s=t.value.trim();s&&this.isValidImageUrl(s)?(n.src=s,i.style.display="block",n.onerror=()=>{i.style.display="none"}):i.style.display="none"})}attachFileUpload(){if(!this.config.allowUpload)return;const e=document.querySelector(".image-dialog-form");if(!e)return;const t=e.querySelector("#image-upload"),i=e.querySelector("#image-src");t==null||t.addEventListener("change",async n=>{var r;const s=(r=n.target.files)==null?void 0:r[0];if(!s)return;const o=new FileReader;o.onload=c=>{var u;const h=(u=c.target)==null?void 0:u.result;i.value=h,i.dispatchEvent(new Event("input"))},o.readAsDataURL(s)})}isValidImageUrl(e){try{return new URL(e),/\.(jpg|jpeg|png|gif|svg|webp|bmp)$/i.test(e)||e.startsWith("data:image/")}catch(t){return!1}}}class D{constructor(e){this.onSubmit=e.onSubmit;const t=this.createContent();this.dialog=new m({title:"Insert Math Equation",content:t,buttons:[{label:"Cancel",onClick:()=>this.dialog.close()},{label:"Insert",onClick:()=>this.handleSubmit(),primary:!0}]}),this.latexInput=t.querySelector("#math-latex"),this.previewDiv=t.querySelector("#math-preview"),this.displayTypeSelect=t.querySelector("#math-display-type"),this.latexInput.addEventListener("input",()=>this.updatePreview())}createContent(){const e=document.createElement("div");return e.className="math-dialog-content",e.style.minWidth="500px",e.innerHTML=` | ||
| <style> | ||
| .math-dialog-content { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1rem; | ||
| } | ||
| .math-form-group { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 0.5rem; | ||
| } | ||
| .math-form-group label { | ||
| font-weight: 500; | ||
| color: #333; | ||
| } | ||
| .math-latex-input { | ||
| width: 100%; | ||
| min-height: 80px; | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| font-family: 'Courier New', monospace; | ||
| font-size: 14px; | ||
| resize: vertical; | ||
| } | ||
| .math-preview { | ||
| padding: 1rem; | ||
| background: #f9f9f9; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| min-height: 60px; | ||
| font-size: 18px; | ||
| text-align: center; | ||
| } | ||
| .math-preview:empty::before { | ||
| content: 'Preview will appear here...'; | ||
| color: #999; | ||
| font-style: italic; | ||
| } | ||
| .math-symbols { | ||
| display: grid; | ||
| grid-template-columns: repeat(8, 1fr); | ||
| gap: 0.5rem; | ||
| padding: 0.5rem; | ||
| background: #f5f5f5; | ||
| border-radius: 4px; | ||
| } | ||
| .math-symbol-btn { | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| background: white; | ||
| border-radius: 4px; | ||
| cursor: pointer; | ||
| font-size: 18px; | ||
| transition: all 0.2s; | ||
| } | ||
| .math-symbol-btn:hover { | ||
| background: #e3f2fd; | ||
| border-color: #2196f3; | ||
| } | ||
| .math-display-select { | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| font-size: 14px; | ||
| } | ||
| </style> | ||
| <div class="math-form-group"> | ||
| <label for="math-latex">LaTeX Expression:</label> | ||
| <textarea | ||
| id="math-latex" | ||
| class="math-latex-input" | ||
| placeholder="Enter LaTeX (e.g., x^2 + y^2 = r^2)" | ||
| ></textarea> | ||
| </div> | ||
| <div class="math-form-group"> | ||
| <label>Common Symbols:</label> | ||
| <div class="math-symbols"> | ||
| <button class="math-symbol-btn" data-symbol="\\frac{a}{b}" title="Fraction">a/b</button> | ||
| <button class="math-symbol-btn" data-symbol="x^{2}" title="Superscript">x²</button> | ||
| <button class="math-symbol-btn" data-symbol="x_{i}" title="Subscript">xᵢ</button> | ||
| <button class="math-symbol-btn" data-symbol="\\sqrt{x}" title="Square root">√x</button> | ||
| <button class="math-symbol-btn" data-symbol="\\sum" title="Sum">∑</button> | ||
| <button class="math-symbol-btn" data-symbol="\\int" title="Integral">∫</button> | ||
| <button class="math-symbol-btn" data-symbol="\\pi" title="Pi">π</button> | ||
| <button class="math-symbol-btn" data-symbol="\\alpha" title="Alpha">α</button> | ||
| <button class="math-symbol-btn" data-symbol="\\beta" title="Beta">β</button> | ||
| <button class="math-symbol-btn" data-symbol="\\gamma" title="Gamma">γ</button> | ||
| <button class="math-symbol-btn" data-symbol="\\theta" title="Theta">θ</button> | ||
| <button class="math-symbol-btn" data-symbol="\\lambda" title="Lambda">λ</button> | ||
| <button class="math-symbol-btn" data-symbol="\\infty" title="Infinity">∞</button> | ||
| <button class="math-symbol-btn" data-symbol="\\leq" title="Less or equal">≤</button> | ||
| <button class="math-symbol-btn" data-symbol="\\geq" title="Greater or equal">≥</button> | ||
| <button class="math-symbol-btn" data-symbol="\\neq" title="Not equal">≠</button> | ||
| </div> | ||
| </div> | ||
| <div class="math-form-group"> | ||
| <label for="math-preview">Preview:</label> | ||
| <div id="math-preview" class="math-preview"></div> | ||
| </div> | ||
| <div class="math-form-group"> | ||
| <label for="math-display-type">Display Type:</label> | ||
| <select id="math-display-type" class="math-display-select"> | ||
| <option value="inline">Inline (within text)</option> | ||
| <option value="block">Block (centered, new line)</option> | ||
| </select> | ||
| </div> | ||
| `,e.querySelectorAll(".math-symbol-btn").forEach(i=>{i.addEventListener("click",n=>{n.preventDefault();const s=i.getAttribute("data-symbol");if(s&&this.latexInput){const o=this.latexInput.selectionStart,r=this.latexInput.selectionEnd,c=this.latexInput.value;this.latexInput.value=c.substring(0,o)+s+c.substring(r),this.latexInput.focus(),this.latexInput.selectionStart=this.latexInput.selectionEnd=o+s.length,this.updatePreview()}})}),e}updatePreview(){const e=this.latexInput.value.trim();if(!e){this.previewDiv.textContent="";return}let t=e.replace(/\\frac\{([^}]+)\}\{([^}]+)\}/g,"($1)/($2)").replace(/\^\{([^}]+)\}/g,"^$1").replace(/\_\{([^}]+)\}/g,"_$1").replace(/\\sqrt\{([^}]+)\}/g,"√($1)").replace(/\\sum/g,"∑").replace(/\\int/g,"∫").replace(/\\pi/g,"π").replace(/\\alpha/g,"α").replace(/\\beta/g,"β").replace(/\\gamma/g,"γ").replace(/\\theta/g,"θ").replace(/\\lambda/g,"λ").replace(/\\infty/g,"∞").replace(/\\leq/g,"≤").replace(/\\geq/g,"≥").replace(/\\neq/g,"≠");this.previewDiv.textContent=t}handleSubmit(){const e=this.latexInput.value.trim();if(!e){alert("Please enter a LaTeX expression.");return}const t=this.displayTypeSelect.value;this.onSubmit({latex:e,display:t}),this.dialog.close()}show(){this.dialog.show(),this.latexInput.value="",this.previewDiv.textContent="",this.displayTypeSelect.value="inline",setTimeout(()=>this.latexInput.focus(),100)}close(){this.dialog.close()}}class I{constructor(e){this.characters={common:["©","®","™","§","¶","†","‡","•","‣","⁃","◦","▪","▫","◊","○","●","□","■","△","▲","▽","▼","◇","◆","★","☆"],arrows:["←","→","↑","↓","↔","↕","⇐","⇒","⇑","⇓","⇔","⇕","⟵","⟶","⟷","↖","↗","↘","↙","⇖","⇗","⇘","⇙"],currency:["$","€","£","¥","₹","₽","₩","₪","₦","฿","₴","₡","₵","₸","₫","₱","₲","₳","₭"],math:["±","×","÷","=","≠","≈","≡","≤","≥","<",">","∞","∑","∏","∫","∂","√","∛","∜","°","′","″","∠","∟","⊥","∥"],greek:["α","β","γ","δ","ε","ζ","η","θ","ι","κ","λ","μ","ν","ξ","ο","π","ρ","σ","τ","υ","φ","χ","ψ","ω","Α","Β","Γ","Δ","Ε","Ζ","Η","Θ"],punctuation:["‚","„","“","”","‘","’","«","»","‹","›","—","–","…","·","¡","¿","‰","′","″","‴"],superscript:["⁰","¹","²","³","⁴","⁵","⁶","⁷","⁸","⁹","⁺","⁻","⁼","⁽","⁾","ⁿ","ⁱ"],subscript:["₀","₁","₂","₃","₄","₅","₆","₇","₈","₉","₊","₋","₌","₍","₎"]},this.onSelect=e.onSelect;const t=this.createContent();this.dialog=new m({title:"Insert Special Character",content:t,buttons:[{label:"Close",onClick:()=>this.dialog.close()}]}),this.searchInput=t.querySelector("#char-search"),this.categorySelect=t.querySelector("#char-category"),this.charactersGrid=t.querySelector("#char-grid"),this.searchInput.addEventListener("input",()=>this.filterCharacters()),this.categorySelect.addEventListener("change",()=>this.updateGrid()),this.updateGrid()}createContent(){const e=document.createElement("div");return e.className="character-dialog-content",e.style.minWidth="500px",e.innerHTML=` | ||
| <style> | ||
| .character-dialog-content { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1rem; | ||
| } | ||
| .char-controls { | ||
| display: flex; | ||
| gap: 0.5rem; | ||
| } | ||
| .char-search, .char-category { | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| font-size: 14px; | ||
| } | ||
| .char-search { | ||
| flex: 1; | ||
| } | ||
| .char-category { | ||
| min-width: 150px; | ||
| } | ||
| .char-grid { | ||
| display: grid; | ||
| grid-template-columns: repeat(10, 1fr); | ||
| gap: 0.5rem; | ||
| max-height: 300px; | ||
| overflow-y: auto; | ||
| padding: 1rem; | ||
| background: #f9f9f9; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| } | ||
| .char-button { | ||
| aspect-ratio: 1; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| background: white; | ||
| border-radius: 4px; | ||
| cursor: pointer; | ||
| font-size: 20px; | ||
| transition: all 0.2s; | ||
| } | ||
| .char-button:hover { | ||
| background: #e3f2fd; | ||
| border-color: #2196f3; | ||
| transform: scale(1.1); | ||
| } | ||
| .char-info { | ||
| padding: 0.5rem; | ||
| background: #f5f5f5; | ||
| border-radius: 4px; | ||
| font-size: 12px; | ||
| color: #666; | ||
| text-align: center; | ||
| } | ||
| </style> | ||
| <div class="char-controls"> | ||
| <input | ||
| type="text" | ||
| id="char-search" | ||
| class="char-search" | ||
| placeholder="Search characters..." | ||
| /> | ||
| <select id="char-category" class="char-category"> | ||
| <option value="all">All Categories</option> | ||
| <option value="common">Common Symbols</option> | ||
| <option value="arrows">Arrows</option> | ||
| <option value="currency">Currency</option> | ||
| <option value="math">Mathematics</option> | ||
| <option value="greek">Greek Letters</option> | ||
| <option value="punctuation">Punctuation</option> | ||
| <option value="superscript">Superscript</option> | ||
| <option value="subscript">Subscript</option> | ||
| </select> | ||
| </div> | ||
| <div id="char-grid" class="char-grid"></div> | ||
| <div class="char-info"> | ||
| Click any character to insert it into your document. | ||
| </div> | ||
| `,e}updateGrid(){const e=this.categorySelect.value;this.charactersGrid.innerHTML="";let t=[];e==="all"?t=Object.values(this.characters).flat():t=this.characters[e]||[],t.forEach(i=>{const n=document.createElement("button");n.className="char-button",n.textContent=i,n.title=`Insert ${i} (U+${i.charCodeAt(0).toString(16).toUpperCase()})`,n.addEventListener("click",s=>{s.preventDefault(),this.handleSelect(i)}),this.charactersGrid.appendChild(n)})}filterCharacters(){const e=this.searchInput.value.toLowerCase();this.charactersGrid.querySelectorAll(".char-button").forEach(i=>{const n=i.textContent||"",s=`u+${n.charCodeAt(0).toString(16)}`,o=!e||n.includes(e)||s.includes(e);i.style.display=o?"flex":"none"})}handleSelect(e){this.onSelect(e),this.dialog.close()}show(){this.dialog.show(),this.searchInput.value="",this.categorySelect.value="all",this.updateGrid(),setTimeout(()=>this.searchInput.focus(),100)}close(){this.dialog.close()}}class F{constructor(e){this.emojis={popular:["😀","😃","😄","😁","😊","😍","🤩","😘","😗","😚","😙","🙂","🤗","🤔","🤨","😐","😑","😶","🙄","😏","👍","👎","👌","✌️","🤞","🤝","👏","🙌","👋","🤚","✋","🖐️","🖖","👊","✊","🤛","🤜","💪"],smileys:["😀","😃","😄","😁","😆","😅","🤣","😂","🙂","🙃","😉","😊","😇","🥰","😍","🤩","😘","😗","😚","😙","😋","😛","😜","🤪","😝","🤑","🤗","🤭","🤫","🤔"],emotions:["😳","😞","😟","😠","😡","🤬","😔","😕","🙁","😬","🥺","😣","😖","😫","😩","🥱","😤","😮","😱","😨","😰","😥","😢","😭","😪","😓","🤤","😴","😷","🤒"],gestures:["👍","👎","👌","✌️","🤞","🤟","🤘","🤙","👈","👉","👆","👇","☝️","👋","🤚","✋","🖐️","🖖","👏","🙌","👐","🤲","🤝","🙏","✍️","💅","🤳","💪","🦾","🦿"],people:["👶","👧","🧒","👦","👩","🧑","👨","👵","🧓","👴","👲","👳","🧕","👮","👷","💂","🕵️","👩⚕️","👨⚕️","👩🎓","👨🎓","👩🏫","👨🏫","👩⚖️","👨⚖️","👩🌾","👨🌾","👩🍳","👨🍳","👩🔧"],animals:["🐶","🐱","🐭","🐹","🐰","🦊","🐻","🐼","🐨","🐯","🦁","🐮","🐷","🐸","🐵","🙈","🙉","🙊","🐔","🐧","🐦","🐤","🐣","🐥","🦆","🦅","🦉","🦇","🐺","🐗"],nature:["🌵","🎄","🌲","🌳","🌴","🌱","🌿","☘️","🍀","🎍","🎋","🍃","🍂","🍁","🍄","🌾","💐","🌷","🌹","🥀","🌺","🌸","🌼","🌻","🌞","🌝","🌛","🌜","⭐","🌟"],food:["🍏","🍎","🍐","🍊","🍋","🍌","🍉","🍇","🍓","🍈","🍒","🍑","🥭","🍍","🥥","🥝","🍅","🍆","🥑","🥦","🥬","🥒","🌶️","🌽","🥕","🧄","🧅","🥔","🍠","🥐"],objects:["⌚","📱","💻","⌨️","🖥️","🖨️","🖱️","🕹️","💾","💿","📀","📷","📹","🎥","📞","☎️","📟","📠","📺","📻","🎙️","🎚️","🎛️","🧭","⏱️","⏰","📡","🔋","🔌","💡"],symbols:["❤️","🧡","💛","💚","💙","💜","🖤","🤍","🤎","💔","❣️","💕","💞","💓","💗","💖","💘","💝","✨","💫","⭐","🌟","✔️","✅","❌","❎","➕","➖","✖️","➗"],activities:["⚽","🏀","🏈","⚾","🥎","🎾","🏐","🏉","🥏","🎱","🪀","🏓","🏸","🏒","🏑","🥍","🏏","🪃","🥅","⛳","🪁","🏹","🎣","🤿","🥊","🥋","🎽","🛹","🛼","🛷"]},this.onSelect=e.onSelect;const t=this.createContent();this.dialog=new m({title:"Insert Emoji",content:t,buttons:[{label:"Close",onClick:()=>this.dialog.close()}]}),this.searchInput=t.querySelector("#emoji-search"),this.categorySelect=t.querySelector("#emoji-category"),this.emojisGrid=t.querySelector("#emoji-grid"),this.searchInput.addEventListener("input",()=>this.filterEmojis()),this.categorySelect.addEventListener("change",()=>this.updateGrid()),this.updateGrid()}createContent(){const e=document.createElement("div");return e.className="emoji-dialog-content",e.style.minWidth="500px",e.innerHTML=` | ||
| <style> | ||
| .emoji-dialog-content { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 1rem; | ||
| } | ||
| .emoji-controls { | ||
| display: flex; | ||
| gap: 0.5rem; | ||
| } | ||
| .emoji-search, .emoji-category { | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| font-size: 14px; | ||
| } | ||
| .emoji-search { | ||
| flex: 1; | ||
| } | ||
| .emoji-category { | ||
| min-width: 150px; | ||
| } | ||
| .emoji-grid { | ||
| display: grid; | ||
| grid-template-columns: repeat(10, 1fr); | ||
| gap: 0.5rem; | ||
| max-height: 350px; | ||
| overflow-y: auto; | ||
| padding: 1rem; | ||
| background: #f9f9f9; | ||
| border: 1px solid #ddd; | ||
| border-radius: 4px; | ||
| } | ||
| .emoji-button { | ||
| aspect-ratio: 1; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| padding: 0.5rem; | ||
| border: 1px solid #ddd; | ||
| background: white; | ||
| border-radius: 4px; | ||
| cursor: pointer; | ||
| font-size: 24px; | ||
| transition: all 0.2s; | ||
| } | ||
| .emoji-button:hover { | ||
| background: #fff3e0; | ||
| border-color: #ff9800; | ||
| transform: scale(1.15); | ||
| } | ||
| .emoji-info { | ||
| padding: 0.5rem; | ||
| background: #f5f5f5; | ||
| border-radius: 4px; | ||
| font-size: 12px; | ||
| color: #666; | ||
| text-align: center; | ||
| } | ||
| </style> | ||
| <div class="emoji-controls"> | ||
| <input | ||
| type="text" | ||
| id="emoji-search" | ||
| class="emoji-search" | ||
| placeholder="Search emojis..." | ||
| /> | ||
| <select id="emoji-category" class="emoji-category"> | ||
| <option value="all">All Emojis</option> | ||
| <option value="popular">Popular</option> | ||
| <option value="smileys">Smileys & Faces</option> | ||
| <option value="emotions">Emotions</option> | ||
| <option value="gestures">Gestures & Hands</option> | ||
| <option value="people">People</option> | ||
| <option value="animals">Animals</option> | ||
| <option value="nature">Nature</option> | ||
| <option value="food">Food & Drink</option> | ||
| <option value="objects">Objects</option> | ||
| <option value="symbols">Symbols</option> | ||
| <option value="activities">Activities & Sports</option> | ||
| </select> | ||
| </div> | ||
| <div id="emoji-grid" class="emoji-grid"></div> | ||
| <div class="emoji-info"> | ||
| Click any emoji to insert it into your document. | ||
| </div> | ||
| `,e}updateGrid(){const e=this.categorySelect.value;this.emojisGrid.innerHTML="";let t=[];e==="all"?t=Object.values(this.emojis).flat():t=this.emojis[e]||[],t.forEach(i=>{const n=document.createElement("button");n.className="emoji-button",n.textContent=i,n.title=`Insert ${i}`,n.addEventListener("click",s=>{s.preventDefault(),this.handleSelect(i)}),this.emojisGrid.appendChild(n)})}filterEmojis(){const e=this.searchInput.value.toLowerCase();this.emojisGrid.querySelectorAll(".emoji-button").forEach(i=>{const n=i.textContent||"",s=!e||n.includes(e);i.style.display=s?"flex":"none"})}handleSelect(e){this.onSelect(e),this.dialog.close()}show(){this.dialog.show(),this.searchInput.value="",this.categorySelect.value="popular",this.updateGrid(),setTimeout(()=>this.searchInput.focus(),100)}close(){this.dialog.close()}}class b{constructor(e={}){this.changeListeners=[],this.options=e,this.engine=new l.EditorEngine({content:e.content,plugins:e.plugins||[],readonly:e.readonly}),e.onChange&&this.onChange(e.onChange),this.engine.on("change",()=>{const t=this.getHTML();this.changeListeners.forEach(i=>i(t))})}mount(e,t){this.contentElement=e,this.toolbarElement=t,this.contentElement.contentEditable=this.options.readonly?"false":"true",this.contentElement.className="rte-content",this.options.content&&(this.contentElement.innerHTML=this.options.content),this.options.toolbar!==!1&&this.toolbarElement&&(this.toolbar=new l.ToolbarRenderer({items:typeof this.options.toolbar=="string"?this.options.toolbar:void 0},this.options.plugins||[]),this.toolbar.setCommandHandler((i,n)=>{this.execCommand(i,n)}),this.toolbar.render(this.toolbarElement)),this.contentElement.addEventListener("input",()=>{const i=this.getHTML();this.changeListeners.forEach(n=>n(i))}),this.options.onInit&&this.options.onInit(this.getAPI())}getHTML(){var e;return((e=this.contentElement)==null?void 0:e.innerHTML)||""}setHTML(e){this.contentElement&&(this.contentElement.innerHTML=e)}execCommand(e,t){const i=this.engine.execCommand(e,t);return this.toolbar,i}focus(){var e;(e=this.contentElement)==null||e.focus()}blur(){var e;(e=this.contentElement)==null||e.blur()}onChange(e){return this.changeListeners.push(e),()=>{const t=this.changeListeners.indexOf(e);t>-1&&this.changeListeners.splice(t,1)}}registerCommand(e,t){if(typeof window!="undefined"){const i=window.__editorCommands||new Map;i.set(e,t),window.__editorCommands=i}}getState(){return{plugins:this.options.plugins,config:this.options,engine:this.engine.getState()}}getAPI(){var e;return{getHTML:()=>this.getHTML(),setHTML:t=>this.setHTML(t),execCommand:(t,i)=>this.execCommand(t,i),focus:()=>this.focus(),blur:()=>this.blur(),destroy:()=>this.destroy(),registerCommand:(t,i)=>this.registerCommand(t,i),onChange:t=>this.onChange(t),getState:()=>this.getState(),toolbar:{items:((e=this.options.plugins)==null?void 0:e.flatMap(t=>t.toolbar||[]))||[]}}}destroy(){var e;this.engine.destroy(),(e=this.toolbar)==null||e.destroy(),this.changeListeners=[],this.options.onDestroy&&this.options.onDestroy()}}function P(a){return new b(a)}class y{constructor(e){this.options=e,this.containerElement=e.element;const t=this.resolvePlugins(e.plugins);this.engine=new l.EditorEngine({content:e.content,plugins:t,readonly:e.readonly}),this.initializeDOM()}resolvePlugins(e){return e?typeof e=="string"?(console.warn("String-based plugin loading not yet implemented for VanillaAdapter"),[]):e:[]}initializeDOM(){this.containerElement.innerHTML="",this.containerElement.classList.add("editora-editor"),this.options.enableToolbar!==!1&&this.options.toolbar!==!1&&(this.toolbarElement=document.createElement("div"),this.toolbarElement.className="editora-toolbar-container",this.containerElement.appendChild(this.toolbarElement),this.toolbar=new l.ToolbarRenderer({items:typeof this.options.toolbar=="string"?this.options.toolbar:void 0},this.options.plugins||[]),this.toolbar.setCommandHandler((e,t)=>{this.execCommand(e,t)}),this.toolbar.render(this.toolbarElement)),this.contentElement=document.createElement("div"),this.contentElement.className="editora-content",this.contentElement.contentEditable=this.options.readonly?"false":"true",this.contentElement.style.minHeight="200px",this.contentElement.style.outline="none",this.contentElement.style.padding="12px",this.options.content&&(this.contentElement.innerHTML=this.options.content),this.containerElement.appendChild(this.contentElement),this.contentElement.addEventListener("input",()=>{this.containerElement.dispatchEvent(new CustomEvent("change",{detail:{html:this.getContent()}}))})}getContent(){var e;return((e=this.contentElement)==null?void 0:e.innerHTML)||""}setContent(e){this.contentElement&&(this.contentElement.innerHTML=e)}execCommand(e,t){return this.engine.execCommand(e,t)}focus(){var e;(e=this.contentElement)==null||e.focus()}on(e,t){const i=n=>{t(n.detail)};return this.containerElement.addEventListener(e,i),()=>{this.containerElement.removeEventListener(e,i)}}destroy(){var e;this.engine.destroy(),(e=this.toolbar)==null||e.destroy(),this.containerElement.innerHTML=""}}function j(a){return new y(a)}function q(){typeof window!="undefined"&&!customElements.get("editora-editor")&&customElements.define("editora-editor",l.RichTextEditorElement)}exports.CommandRegistry=l.CommandRegistry;exports.ConfigResolver=l.ConfigResolver;exports.EditorEngine=l.EditorEngine;exports.EditorState=l.EditorState;exports.FloatingToolbar=l.FloatingToolbar;exports.PluginLoader=l.PluginLoader;exports.PluginManager=l.PluginManager;exports.RichTextEditorElement=l.RichTextEditorElement;exports.Schema=l.Schema;exports.StatusBar=l.StatusBar;exports.ToolbarRenderer=l.ToolbarRenderer;exports.CharacterDialog=I;exports.ColorPicker=k;exports.Dialog=m;exports.DocumentModel=p;exports.Dropdown=C;exports.Editor=v;exports.EmojiDialog=F;exports.ImageDialog=T;exports.KeyboardShortcutManager=S;exports.LinkDialog=M;exports.MathDialog=D;exports.PluginRuntime=f;exports.ReactAdapter=b;exports.TableDialog=L;exports.VanillaAdapter=y;exports.createEditor=j;exports.createMediaPlugin=x;exports.createPluginRuntime=E;exports.createReactAdapter=P;exports.createSpellcheckPlugin=w;exports.initWebComponent=q; | ||
| //# sourceMappingURL=index.cjs.js.map |
+52
-6
| { | ||
| "name": "@editora/core", | ||
| "version": "1.0.0", | ||
| "version": "1.0.1", | ||
| "description": "Framework-agnostic core editor engine for Editora Rich Text Editor", | ||
@@ -12,3 +12,3 @@ "author": "Ajay Kumar <ajaykr089@gmail.com>", | ||
| }, | ||
| "homepage": "https://github.com/ajaykr089/Editora#readme", | ||
| "homepage": "https://editora-free.netlify.app/", | ||
| "bugs": { | ||
@@ -26,3 +26,22 @@ "url": "https://github.com/ajaykr089/Editora/issues" | ||
| "umd", | ||
| "browser" | ||
| "browser", | ||
| "editora", | ||
| "rich-text-editor", | ||
| "best-free-editor", | ||
| "premium-features-free", | ||
| "enterprise-editor", | ||
| "text-editor", | ||
| "document-editor", | ||
| "open-source-editor", | ||
| "tinymce-alternative", | ||
| "quill-alternative", | ||
| "free-wysiwyg-editor", | ||
| "html-editor", | ||
| "accessible-editor", | ||
| "a11y-editor", | ||
| "keyboard-shortcuts", | ||
| "plugins-support", | ||
| "web-component", | ||
| "custom-element", | ||
| "framework-agnostic" | ||
| ], | ||
@@ -39,4 +58,11 @@ "main": "dist/index.cjs.js", | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.cjs.js" | ||
| "require": "./dist/index.cjs.js", | ||
| "browser": "./dist/editora.min.js" | ||
| }, | ||
| "./webcomponent": { | ||
| "types": "./dist/webcomponent/index.d.ts", | ||
| "import": "./dist/webcomponent.esm.js", | ||
| "require": "./dist/webcomponent.cjs.js", | ||
| "browser": "./dist/webcomponent.min.js" | ||
| }, | ||
| "./KeyboardShortcuts": { | ||
@@ -46,2 +72,22 @@ "types": "./dist/index.d.ts", | ||
| "require": "./dist/index.cjs.js" | ||
| }, | ||
| "./core": { | ||
| "types": "./dist/core/index.d.ts", | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.cjs.js" | ||
| }, | ||
| "./ui": { | ||
| "types": "./dist/ui/index.d.ts", | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.cjs.js" | ||
| }, | ||
| "./adapters": { | ||
| "types": "./dist/adapters/index.d.ts", | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.cjs.js" | ||
| }, | ||
| "./config": { | ||
| "types": "./dist/config/index.d.ts", | ||
| "import": "./dist/index.esm.js", | ||
| "require": "./dist/index.cjs.js" | ||
| } | ||
@@ -55,3 +101,3 @@ }, | ||
| "scripts": { | ||
| "build": "vite build", | ||
| "build": "vite build && vite build --config vite.umd.config.ts && vite build --config vite.webcomponent.config.ts", | ||
| "dev": "vite build --watch", | ||
@@ -68,3 +114,3 @@ "clean": "rm -rf dist", | ||
| }, | ||
| "gitHead": "e26546f8b2455c9a27eceb61818db31fd81fb518" | ||
| "gitHead": "694494db58b809f0dcf24501696284faa1ab68a5" | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
16187366
25858.76%24
242.86%26492
3349.48%4
33.33%25
Infinity%1
Infinity%