@editora/react
Advanced tools
+183
| import * as React from "react"; | ||
| import type { | ||
| Plugin, | ||
| Editor, | ||
| ToolbarItem, | ||
| KeyboardShortcutConfig, | ||
| } from "@editora/core"; | ||
| export interface EditorAPI { | ||
| getHTML(): string; | ||
| setHTML(html: string): void; | ||
| execCommand(name: string, value?: unknown): void; | ||
| registerCommand(name: string, fn: (params?: unknown) => void): void; | ||
| focus(): void; | ||
| blur(): void; | ||
| destroy(): void; | ||
| onChange(fn: (html: string) => void): () => void; | ||
| getState(): unknown; | ||
| toolbar?: { items?: unknown[] }; | ||
| menubar?: unknown; | ||
| contextMenu?: unknown; | ||
| media?: unknown; | ||
| paste?: unknown; | ||
| history?: unknown; | ||
| language?: unknown; | ||
| spellcheck?: unknown; | ||
| autosave?: unknown; | ||
| accessibility?: unknown; | ||
| performance?: unknown; | ||
| content?: unknown; | ||
| security?: unknown; | ||
| secureInput?(html: string, opts: unknown): string; | ||
| } | ||
| export interface RichTextEditorProps { | ||
| id?: string; | ||
| className?: string; | ||
| value?: string; | ||
| defaultValue?: string; | ||
| readonly?: boolean; | ||
| placeholder?: string; | ||
| onChange?: (html: string) => void; | ||
| onInit?: (editor: EditorAPI) => void; | ||
| onDestroy?: () => void; | ||
| plugins?: Plugin[] | string[]; | ||
| pluginConfig?: Record<string, unknown>; | ||
| toolbar?: { | ||
| items?: string[] | ToolbarItem[]; | ||
| floating?: boolean; | ||
| sticky?: boolean; | ||
| showMoreOptions?: boolean; | ||
| }; | ||
| statusbar?: { | ||
| enabled?: boolean; | ||
| position?: "top" | "bottom"; | ||
| }; | ||
| menubar?: { | ||
| enabled: boolean; | ||
| items?: string[]; | ||
| }; | ||
| contextMenu?: { | ||
| enabled?: boolean; | ||
| }; | ||
| media?: { | ||
| uploadUrl?: string; | ||
| libraryUrl?: string; | ||
| maxFileSize?: number; | ||
| allowedTypes?: string[]; | ||
| headers?: Record<string, string>; | ||
| withCredentials?: boolean; | ||
| }; | ||
| paste?: { | ||
| clean?: boolean; | ||
| keepFormatting?: boolean; | ||
| convertWord?: boolean; | ||
| }; | ||
| history?: { | ||
| maxSteps?: number; | ||
| debounceMs?: number; | ||
| }; | ||
| language?: { | ||
| locale?: string; | ||
| direction?: "ltr" | "rtl"; | ||
| }; | ||
| spellcheck?: { | ||
| enabled?: boolean; | ||
| provider?: "browser" | "local" | "api"; | ||
| apiUrl?: string; | ||
| apiHeaders?: Record<string, string>; | ||
| }; | ||
| autosave?: { | ||
| enabled?: boolean; | ||
| intervalMs?: number; | ||
| storageKey?: string; | ||
| provider?: "localStorage" | "api"; | ||
| apiUrl?: string; | ||
| }; | ||
| accessibility?: { | ||
| enableARIA?: boolean; | ||
| keyboardNavigation?: boolean; | ||
| checker?: boolean; | ||
| }; | ||
| performance?: { | ||
| debounceInputMs?: number; | ||
| viewportOnlyScan?: boolean; | ||
| }; | ||
| content?: { | ||
| allowedTags?: string[]; | ||
| allowedAttributes?: Record<string, string[]>; | ||
| sanitize?: boolean; | ||
| }; | ||
| security?: { | ||
| sanitizeOnPaste?: boolean; | ||
| sanitizeOnInput?: boolean; | ||
| }; | ||
| floatingToolbar?: boolean | { enabled?: boolean }; | ||
| mediaConfig?: { | ||
| uploadUrl: string; | ||
| libraryUrl: string; | ||
| maxFileSize: number; | ||
| allowedTypes: string[]; | ||
| }; | ||
| } | ||
| export interface EditorConfig extends RichTextEditorProps { | ||
| plugins: Plugin[]; | ||
| pluginConfig: Record<string, unknown>; | ||
| } | ||
| export interface InlineMenuOption { | ||
| label: string; | ||
| value: string; | ||
| } | ||
| export interface InlineMenuProps { | ||
| isOpen: boolean; | ||
| options: InlineMenuOption[]; | ||
| onSelect: (value: string) => void; | ||
| onClose: () => void; | ||
| anchorRef: React.RefObject<HTMLElement>; | ||
| className?: string; | ||
| } | ||
| export interface UseKeyboardShortcutsOptions extends KeyboardShortcutConfig { | ||
| onCommand?: (command: string, params?: unknown) => void; | ||
| editorElement?: HTMLElement | null; | ||
| } | ||
| export interface ToolbarProps { | ||
| editor: Editor; | ||
| position?: "top" | "bottom"; | ||
| sticky?: boolean; | ||
| floating?: boolean; | ||
| readonly?: boolean; | ||
| showMoreOptions?: boolean; | ||
| itemsOverride?: string[] | ToolbarItem[]; | ||
| } | ||
| export interface EditorContentProps { | ||
| editor: Editor; | ||
| defaultValue?: string; | ||
| value?: string; | ||
| readonly?: boolean; | ||
| placeholder?: string; | ||
| onChange?: (html: string) => void; | ||
| } | ||
| export const RichTextEditor: React.FC<RichTextEditorProps>; | ||
| export const EditoraEditor: React.FC<RichTextEditorProps>; | ||
| export const Toolbar: React.FC<ToolbarProps>; | ||
| export const EditorContent: React.FC<EditorContentProps>; | ||
| export const InlineMenu: React.FC<InlineMenuProps>; | ||
| export function useKeyboardShortcuts(options?: UseKeyboardShortcutsOptions): { | ||
| getShortcuts: () => unknown[]; | ||
| getShortcutForCommand: (command: string) => unknown; | ||
| getShortcutsHelp: () => string; | ||
| enable: () => void; | ||
| disable: () => void; | ||
| isEnabled: () => boolean; | ||
| }; | ||
| export function mergeConfig(props: RichTextEditorProps): EditorConfig; |
@@ -1,1 +0,1 @@ | ||
| "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),i=require("react"),j=require("@editora/core"),P=({isOpen:e,options:t,onSelect:g,onClose:u,anchorRef:s,className:a=""})=>{const b=i.useRef(null),[d,w]=i.useState({top:0,left:0});return i.useEffect(()=>{if(e&&s.current){const r=s.current.getBoundingClientRect(),f=120,p=t.length*36;let C=r.bottom+4,c=r.left;const m=window.innerWidth,h=window.innerHeight;c+f>m&&(c=m-f-8),C+p>h&&(C=r.top-p-4),w({top:C,left:c})}},[e,s,t.length]),i.useEffect(()=>{if(e&&s.current&&b.current){const r=s.current.getBoundingClientRect(),f=b.current.getBoundingClientRect();let p=r.bottom+4,C=r.left;const c=window.innerWidth,m=window.innerHeight;C+f.width>c&&(C=c-f.width-8),p+f.height>m&&(p=r.top-f.height-4),w({top:p,left:C})}},[e]),i.useEffect(()=>{const r=p=>{b.current&&!b.current.contains(p.target)&&s.current&&!s.current.contains(p.target)&&u()},f=p=>{p.key==="Escape"&&u()};return e&&(document.addEventListener("mousedown",r),document.addEventListener("keydown",f)),()=>{document.removeEventListener("mousedown",r),document.removeEventListener("keydown",f)}},[e,u,s]),e?o.jsx("div",{ref:b,className:`rte-inline-menu ${a}`,style:{position:"fixed",top:d.top,left:d.left,zIndex:1e3,background:"white",border:"1px solid #ccc",borderRadius:"4px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",minWidth:"120px",maxWidth:"200px",pointerEvents:"auto"},children:t.map(r=>o.jsx("div",{className:"rte-inline-menu-item",onClick:()=>{g(r.value),u()},style:{padding:"8px 12px",cursor:"pointer",borderBottom:"1px solid #f0f0f0",fontSize:"14px",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},onMouseEnter:f=>{f.currentTarget.style.backgroundColor="#f5f5f5"},onMouseLeave:f=>{f.currentTarget.style.backgroundColor="transparent"},children:r.label},r.value))}):null},H=({editor:e,position:t="top",sticky:g=!1,floating:u=!1})=>{const[s,a]=i.useState(null),[b,d]=i.useState(null),[w,r]=i.useState(null),[f,p]=i.useState(null),[C,c]=i.useState(!1),m=i.useRef({}),h=i.useRef(null),x=i.useRef(null),y=i.useRef(null),v=e.pluginManager.getToolbarItems();i.useEffect(()=>{const n=()=>{if(!h.current||!x.current)return;const N=h.current.clientWidth,I=16,Q=40,B=4,Y=N-I-Q-B;let F=0,O=0;const U=x.current.children;for(let D=0;D<U.length;D++){const q=U[D].offsetWidth+B;if(F+q<=Y)F+=q,O++;else break}p(Math.max(1,O))},l=requestAnimationFrame(()=>{n()}),S=new ResizeObserver(()=>{n()});h.current&&S.observe(h.current);const L=new MutationObserver(()=>{n()});return x.current&&L.observe(x.current,{childList:!0,subtree:!0}),()=>{cancelAnimationFrame(l),S.disconnect(),L.disconnect()}},[v.length]);const k=n=>(m.current[n]||(m.current[n]=i.createRef()),m.current[n]),E=(n,l)=>{const S=h.current?.closest("[data-editora-editor]"),L=S?.querySelector(".rte-content");if(L&&L.focus(),w&&(n==="setTextAlignment"||n==="setFontFamily"||n==="setBlockType")){const I=window.getSelection();I&&(I.removeAllRanges(),I.addRange(w)),r(null)}typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(n,l),a(null);const N=S?.querySelector(".rte-content");N&&N.focus()},R=n=>{const l=window.getSelection();l&&l.rangeCount>0&&r(l.getRangeAt(0).cloneRange()),a(s===n?null:n)},T=n=>{const l=window.getSelection();l&&l.rangeCount>0&&r(l.getRangeAt(0).cloneRange()),d(b===n?null:n),a(null)},M=(n,l)=>{if(w){const S=window.getSelection();S&&(S.removeAllRanges(),S.addRange(w)),r(null)}E(n,l),d(null)},A=(n,l)=>n&&n.startsWith("<svg")&&n.endsWith("</svg>")?o.jsx("span",{dangerouslySetInnerHTML:{__html:n}}):n&&n.length===1&&/^[BIUSH]$/.test(n)?o.jsx("span",{style:{fontWeight:"bold",fontSize:"14px",lineHeight:"1"},children:n}):n||"⚪";if(u)return null;const J={...g&&{position:"sticky",top:0,zIndex:100,backgroundColor:"#fff",boxShadow:"0 2px 4px rgba(0,0,0,0.1)"},...t==="bottom"&&{order:2}},z=n=>n.map((l,S)=>o.jsx("div",{className:"rte-toolbar-item",style:{display:f!==null&&S>=f?"none":"flex"},children:l.type==="dropdown"?o.jsxs("div",{className:"rte-toolbar-dropdown",children:[o.jsxs("button",{className:"rte-toolbar-button","data-command":l.command,"data-active":"false",onClick:()=>R(l.command),children:[l.label," ▼"]}),s===l.command&&o.jsx("div",{className:"rte-toolbar-dropdown-menu",children:l.options?.map(L=>o.jsx("div",{className:"rte-toolbar-dropdown-item",onClick:()=>E(l.command,L.value),children:L.label},L.value))})]}):l.type==="inline-menu"?o.jsx("button",{ref:k(l.command),className:"rte-toolbar-button","data-command":l.command,"data-active":"false",onClick:()=>T(l.command),title:l.label,children:A(l.icon,l.command)}):l.type==="input"?o.jsx("input",{type:"text",className:`rte-toolbar-input ${l.label.toLowerCase().replace(/\s+/g,"-")}`,placeholder:l.placeholder,onChange:L=>E(l.command,L.target.value),onKeyDown:L=>{L.key==="Enter"&&E(l.command,L.target.value)},title:l.label}):l.type==="group"?o.jsx("div",{className:`rte-toolbar-group-button ${l.label.toLowerCase().replace(/\s+/g,"-")}`,title:`${l.label}`,children:o.jsx("div",{className:`rte-toolbar-group-items ${l.label.toLowerCase().replace(/\s+/g,"-")}`,children:z(l.items||[])})}):o.jsx("button",{className:"rte-toolbar-button","data-command":l.command,"data-active":"false",onClick:()=>E(l.command),title:l.label,children:A(l.icon,l.command)})},S));return o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"rte-toolbar-wrapper",style:J,children:[o.jsxs("div",{className:"rte-toolbar",ref:h,children:[o.jsx("div",{className:"rte-toolbar-items-container",ref:x,children:z(v)}),f!==null&&f<v.length&&o.jsx("button",{ref:y,className:`rte-toolbar-more-button ${C?"active":""}`,onClick:()=>c(!C),title:"Show more options","aria-label":"More toolbar options",children:"☰"})]}),f!==null&&f<v.length&&o.jsx("div",{className:`rte-toolbar-expanded-row ${C?"show":""}`,children:v.map((n,l)=>l>=(f||0)&&o.jsx("div",{className:"rte-toolbar-item",children:n.type==="dropdown"?o.jsxs("div",{className:"rte-toolbar-dropdown",children:[o.jsxs("button",{className:"rte-toolbar-button","data-command":n.command,"data-active":"false",onClick:()=>R(n.command),children:[n.label," ▼"]}),s===n.command&&o.jsx("div",{className:"rte-toolbar-dropdown-menu",children:n.options?.map(S=>o.jsx("div",{className:"rte-toolbar-dropdown-item",onClick:()=>E(n.command,S.value),children:S.label},S.value))})]}):n.type==="inline-menu"?o.jsx("button",{ref:k(n.command),className:"rte-toolbar-button","data-command":n.command,"data-active":"false",onClick:()=>T(n.command),title:n.label,children:A(n.icon,n.command)}):n.type==="input"?o.jsx("input",{type:"text",className:"rte-toolbar-input",placeholder:n.placeholder,onChange:S=>E(n.command,S.target.value),onKeyDown:S=>{S.key==="Enter"&&E(n.command,S.target.value)},title:n.label}):o.jsx("button",{className:"rte-toolbar-button","data-command":n.command,"data-active":"false",onClick:()=>E(n.command),title:n.label,children:A(n.icon,n.command)})},l))})]}),v.map(n=>n.type==="inline-menu"?o.jsx(P,{isOpen:b===n.command,options:n.options||[],onSelect:l=>M(n.command,l),onClose:()=>d(null),anchorRef:k(n.command)},`menu-${n.command}`):null)]})};function Z(e,t){const g=i.useRef(),u=i.useRef("");return i.useEffect(()=>{if(!t?.enabled)return;const a=t.intervalMs||3e4,b=t.storageKey||"rte-autosave",d=t.provider||"localStorage",w=async()=>{const r=e();if(r!==u.current){if(u.current=r,d==="localStorage")try{localStorage.setItem(b,r),localStorage.setItem(`${b}-timestamp`,Date.now().toString()),console.log("[Autosave] Content saved to localStorage")}catch(f){console.error("[Autosave] Failed to save to localStorage:",f)}else if(d==="api"&&t.apiUrl)try{await fetch(t.apiUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:r,timestamp:Date.now()})}),console.log("[Autosave] Content saved to API")}catch(f){console.error("[Autosave] Failed to save to API:",f)}}};return g.current=setInterval(w,a),()=>{g.current&&clearInterval(g.current)}},[t?.enabled,t?.intervalMs,t?.storageKey,t?.provider,t?.apiUrl,e]),{restore:()=>{if(!t?.enabled)return null;const a=t.storageKey||"rte-autosave";if((t.provider||"localStorage")==="localStorage")try{const d=localStorage.getItem(a),w=localStorage.getItem(`${a}-timestamp`);if(d&&w)return console.log("[Autosave] Restored from localStorage, saved at:",new Date(parseInt(w))),d}catch(d){console.error("[Autosave] Failed to restore from localStorage:",d)}return null}}}const ee=["p","br","strong","em","u","s","b","i","h1","h2","h3","h4","h5","h6","ul","ol","li","a","img","video","audio","table","thead","tbody","tr","th","td","blockquote","pre","code","span","div","sup","sub","hr"],te={"*":["class","style","id","data-*"],a:["href","target","rel","title"],img:["src","alt","width","height","loading"],video:["src","controls","width","height","autoplay","loop","muted"],audio:["src","controls","autoplay","loop","muted"],table:["border","cellpadding","cellspacing"],td:["colspan","rowspan","align","valign"],th:["colspan","rowspan","align","valign"]};function K(e,t,g){if(t?.sanitize===!1)return e;const u=t?.allowedTags&&t.allowedTags.length>0?t.allowedTags:ee,s=t?.allowedAttributes||te,a=document.createElement("div");return a.innerHTML=e,$(a,u,s),a.innerHTML}function $(e,t,g){const u=Array.from(e.childNodes);for(const s of u)if(s.nodeType===Node.ELEMENT_NODE){const a=s,b=a.tagName.toLowerCase();if(!t.includes(b)){for(;a.firstChild;)e.insertBefore(a.firstChild,a);e.removeChild(a);continue}ne(a,g),$(a,t,g)}else{if(s.nodeType===Node.TEXT_NODE)continue;e.removeChild(s)}}function ne(e,t){const g=e.tagName.toLowerCase(),u=Array.from(e.attributes),s=t[g]||[],a=t["*"]||[],b=[...s,...a];for(const d of u){const w=d.name.toLowerCase();let r=!1;b.includes(w)&&(r=!0);for(const f of b)if(f.endsWith("*")){const p=f.slice(0,-1);if(w.startsWith(p)){r=!0;break}}(w.startsWith("on")||w==="javascript:"||w==="href"&&d.value.trim().toLowerCase().startsWith("javascript:")||w==="src"&&d.value.trim().toLowerCase().startsWith("javascript:"))&&(r=!1),r||e.removeAttribute(d.name)}e.hasAttribute("href")&&(e.getAttribute("href")||"").trim().toLowerCase().startsWith("javascript:")&&e.removeAttribute("href"),e.hasAttribute("src")&&(e.getAttribute("src")||"").trim().toLowerCase().startsWith("javascript:")&&e.removeAttribute("src")}function oe(e,t,g){return g?.sanitizeOnPaste===!1?e:K(e,t)}function re(e,t,g){return g?.sanitizeOnInput===!1?e:K(e,t)}const V=({editor:e,defaultValue:t,value:g,onChange:u,pasteConfig:s,contentConfig:a,securityConfig:b,performanceConfig:d,autosaveConfig:w})=>{const r=i.useRef(null),f=g!==void 0,p=i.useRef(),{restore:C}=Z(()=>r.current?.innerHTML||"",w);return i.useEffect(()=>{if(!r.current)return;const c=C(),m=c||g||t;m&&r.current.innerHTML!==m&&(r.current.innerHTML=m,c&&u&&u(c))},[]),i.useEffect(()=>{!r.current||!f||g!==r.current.innerHTML&&(r.current.innerHTML=g)},[g,f]),i.useEffect(()=>{if(!r.current)return;const c=()=>{if(!r.current||!u)return;let y=r.current.innerHTML;if(b?.sanitizeOnInput!==!1&&a?.sanitize!==!1&&(y=re(y,a,b),y!==r.current.innerHTML)){const v=window.getSelection(),k=v&&v.rangeCount>0?v.getRangeAt(0):null;if(r.current.innerHTML=y,k&&v)try{v.removeAllRanges(),v.addRange(k)}catch{}}d?.debounceInputMs?(p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{u(y)},d.debounceInputMs)):u(y)},m=y=>{y.preventDefault();let v=y.clipboardData?.getData("text/html");const k=y.clipboardData?.getData("text/plain");if(s?.clean||!s?.keepFormatting){k&&document.execCommand("insertText",!1,k);return}if(v){b?.sanitizeOnPaste!==!1&&a?.sanitize!==!1&&(v=oe(v,a,b));const E=window.getSelection();if(E&&E.rangeCount>0){const R=E.getRangeAt(0);R.deleteContents();const T=document.createElement("div");T.innerHTML=v;const M=document.createDocumentFragment();for(;T.firstChild;)M.appendChild(T.firstChild);R.insertNode(M),R.collapse(!1),E.removeAllRanges(),E.addRange(R)}}else k&&document.execCommand("insertText",!1,k)},h=y=>{const v=y.target;(v.tagName==="IMG"||v.tagName==="VIDEO")&&(v.style.resize="both",v.style.overflow="auto",v.style.display="inline-block")},x=r.current;return x.addEventListener("input",c),x.addEventListener("paste",m),x.addEventListener("click",h),x.focus(),()=>{p.current&&clearTimeout(p.current),x.removeEventListener("input",c),x.removeEventListener("paste",m),x.removeEventListener("click",h)}},[e,u,s,a,b,d]),i.useEffect(()=>{if(!r.current||typeof window>"u")return;const c=new j.KeyboardShortcutManager,m=r.current,h=x=>{c.handleKeyDown(x,(y,v)=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(y,v)})};return m.addEventListener("keydown",h),()=>{m.removeEventListener("keydown",h)}},[]),o.jsx("div",{ref:r,contentEditable:!0,suppressContentEditableWarning:!0,className:"rte-content",style:{minHeight:"200px",maxHeight:"100%",padding:"16px",outline:"none",border:"1px solid #ddd",borderRadius:"0px 0px 4px 4px",fontSize:"14px",lineHeight:"1.5",overflow:"auto",flex:1,boxSizing:"border-box",wordWrap:"break-word",overflowWrap:"break-word"},children:o.jsx("p",{children:o.jsx("br",{})})})},ae=({editor:e,isEnabled:t})=>{const[g,u]=i.useState(!1),[s,a]=i.useState({top:0,left:0}),b=i.useRef(null),d=i.useRef(null),w=i.useRef(null),r=i.useRef(null);i.useEffect(()=>{if(!t){u(!1);return}r.current=b.current?.closest("[data-editora-editor]");const p=()=>{w.current&&clearTimeout(w.current);const c=window.getSelection();if(!c||c.rangeCount===0){u(!1),d.current=null;return}const m=c.getRangeAt(0),h=c.toString().trim(),x=r.current?.querySelector(".rte-content");if(!x||!x.contains(m.commonAncestorContainer)){u(!1),d.current=null;return}if(h.length>0){const y=m.getBoundingClientRect(),v=x.getBoundingClientRect(),k=300;if(y&&v){const E=y.top-50;let R=y.left+y.width/2;const T=k/2,M=v.left,A=v.right;R-T<M&&(R=M+T+10),R+T>A&&(R=A-T-10),a({top:E,left:R}),w.current=setTimeout(()=>{u(!0),d.current=m.cloneRange()},300)}}else u(!1),d.current=null},C=c=>{b.current&&!b.current.contains(c.target)&&(window.getSelection(),r.current?.querySelector(".rte-content")?.contains(c.target)||(u(!1),d.current=null))};return document.addEventListener("selectionchange",p),document.addEventListener("mousedown",C),document.addEventListener("keydown",c=>{c.key==="Escape"&&(u(!1),d.current=null)}),()=>{document.removeEventListener("selectionchange",p),document.removeEventListener("mousedown",C),w.current&&clearTimeout(w.current)}},[t]);const f=(p,C)=>{if(!d.current)return;const c=r.current?.querySelector(".rte-content");c&&c.focus(),{toggleBold:()=>document.execCommand("bold",!1),toggleItalic:()=>document.execCommand("italic",!1),toggleUnderline:()=>document.execCommand("underline",!1),toggleStrikethrough:()=>document.execCommand("strikeThrough",!1),createLink:()=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand("openLinkDialog")},clearFormatting:()=>{document.execCommand("removeFormat",!1),document.execCommand("unlink",!1)},toggleCode:()=>{const h=window.getSelection();if(h&&h.rangeCount>0){const x=h.getRangeAt(0),y=document.createElement("code");x.surroundContents(y)}},setBlockType:()=>{if(C==="blockquote"){const h=window.getSelection();if(h&&h.rangeCount>0){const x=h.getRangeAt(0);(x.commonAncestorContainer.nodeType===Node.TEXT_NODE?x.commonAncestorContainer.parentElement:x.commonAncestorContainer)?.closest?.("blockquote")?document.execCommand("formatBlock",!1,"p"):document.execCommand("formatBlock",!1,"blockquote")}}else C&&document.execCommand("formatBlock",!1,C)}}[p]?.(),u(!1),d.current=null,c&&c.focus()};return!t||!g?null:o.jsxs("div",{ref:b,className:"floating-toolbar",style:{position:"fixed",top:`${s.top}px`,left:`${s.left}px`,transform:"translateX(-50%)",zIndex:1e3,background:"white",border:"1px solid #e1e5e9",borderRadius:"6px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15)",padding:"6px",display:"flex",gap:"4px",alignItems:"center"},children:[o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("toggleBold"),title:"Bold (Ctrl+B)",children:o.jsx("strong",{children:"B"})}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("toggleItalic"),title:"Italic (Ctrl+I)",children:o.jsx("em",{children:"I"})}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("toggleUnderline"),title:"Underline (Ctrl+U)",children:o.jsx("u",{children:"U"})}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("toggleStrikethrough"),title:"Strikethrough",children:o.jsx("s",{children:"S"})}),o.jsx("div",{className:"floating-toolbar-separator"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("clearFormatting"),title:"Clear Formatting",children:"⌫"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("createLink"),title:"Insert Link",children:"🔗"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("toggleCode"),title:"Code",children:"Code"}),o.jsx("div",{className:"floating-toolbar-separator"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>f("setBlockType","blockquote"),title:"Quote",children:"❝"})]})},le=({plugins:e,children:t})=>{const g=e.filter(s=>s.context?.provider);return g.length===0?o.jsx(o.Fragment,{children:t}):g.reduce((s,a)=>{const b=a.context.provider;return o.jsx(b,{children:s},a.name)},o.jsx(o.Fragment,{children:t}))},ie={toolbar:{items:[],floating:!1,sticky:!1},statusbar:{enabled:!1,position:"bottom"},menubar:{enabled:!1,items:[]},contextMenu:{enabled:!0},media:{uploadUrl:"",libraryUrl:"",maxFileSize:10*1024*1024,allowedTypes:["image/jpeg","image/png","image/gif","image/webp"],headers:{},withCredentials:!1},paste:{clean:!0,keepFormatting:!1,convertWord:!0},history:{maxSteps:100,debounceMs:300},language:{locale:"en",direction:"ltr"},spellcheck:{enabled:!1,provider:"browser",apiUrl:"",apiHeaders:{}},autosave:{enabled:!1,intervalMs:3e4,storageKey:"rte-autosave",provider:"localStorage",apiUrl:""},accessibility:{enableARIA:!0,keyboardNavigation:!0,checker:!1},performance:{debounceInputMs:100,viewportOnlyScan:!0},content:{allowedTags:[],allowedAttributes:{},sanitize:!0},security:{sanitizeOnPaste:!0,sanitizeOnInput:!0}};function _(e,t){const g={...e};for(const u in t){const s=t[u],a=g[u];s!==void 0&&(typeof s=="object"&&s!==null&&!Array.isArray(s)&&typeof a=="object"&&a!==null&&!Array.isArray(a)?g[u]=_(a,s):g[u]=s)}return g}function G(e){const t=_(ie,{toolbar:e.toolbar,statusbar:e.statusbar,menubar:e.menubar,contextMenu:e.contextMenu,media:e.media,paste:e.paste,history:e.history,language:e.language,spellcheck:e.spellcheck,autosave:e.autosave,accessibility:e.accessibility,performance:e.performance,content:e.content,security:e.security});return e.floatingToolbar!==void 0&&(t.toolbar={...t.toolbar,floating:e.floatingToolbar.enabled??t.toolbar.floating}),e.mediaConfig&&(t.media={...t.media,uploadUrl:e.mediaConfig.uploadUrl||t.media.uploadUrl,libraryUrl:e.mediaConfig.libraryUrl||t.media.libraryUrl,maxFileSize:e.mediaConfig.maxFileSize||t.media.maxFileSize,allowedTypes:e.mediaConfig.allowedTypes||t.media.allowedTypes}),{...t,id:e.id,className:e.className,value:e.value,defaultValue:e.defaultValue,onChange:e.onChange,onInit:e.onInit,onDestroy:e.onDestroy,plugins:Array.isArray(e.plugins)?e.plugins.filter(u=>typeof u!="string"):[],pluginConfig:e.pluginConfig||{}}}const W=new Map;typeof window<"u"&&(window.registerEditorCommand=(e,t)=>{W.set(e,t)},window.executeEditorCommand=(e,t)=>{const g=W.get(e);return g?g(t):(console.warn(`No handler registered for command: ${e}`),!1)});const se=e=>{const t=i.useMemo(()=>G(e),[e.id,e.className,e.value,e.defaultValue,e.plugins,e.toolbar,e.menubar,e.contextMenu,e.media,e.paste,e.history,e.language,e.spellcheck,e.autosave,e.accessibility,e.performance,e.content,e.security,e.floatingToolbar,e.mediaConfig]),g=i.useRef(null),u=i.useRef(null),s=i.useRef(e.onInit),a=i.useRef(e.onDestroy),b=i.useRef(null),d=i.useRef(null),w=i.useRef(null);i.useEffect(()=>{s.current=e.onInit,a.current=e.onDestroy});const r=i.useMemo(()=>{const c=new j.PluginManager;t.plugins.forEach(h=>{c.register(h),h.commands&&typeof window<"u"&&Object.entries(h.commands).forEach(([x,y])=>{W.set(x,y)})});const m=new j.Editor(c);return g.current=m,m},[t.plugins]);i.useEffect(()=>{const c={getHTML:()=>b.current?.querySelector(".rte-content")?.innerHTML||"",setHTML:m=>{const h=b.current?.querySelector(".rte-content");h&&(h.innerHTML=m)},execCommand:(m,h)=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(m,h)},registerCommand:(m,h)=>{typeof window<"u"&&window.registerEditorCommand&&window.registerEditorCommand(m,h)},focus:()=>{b.current?.querySelector(".rte-content")?.focus()},blur:()=>{b.current?.querySelector(".rte-content")?.blur()},destroy:()=>{a.current&&a.current()},onChange:m=>()=>{},getState:()=>({plugins:t.plugins,config:t}),toolbar:{items:r.toolbar?.items||[]}};return u.current=c,s.current&&s.current(c),()=>{a.current&&a.current()}},[]),i.useEffect(()=>{if(t.statusbar.enabled&&w.current&&b.current){d.current||(d.current=new j.StatusBar({enabled:!0,position:t.statusbar.position}),d.current.create(w.current));const c=b.current.querySelector(".rte-content");if(c){const m=()=>{const h=c.textContent||"",{words:x,chars:y}=j.calculateTextStats(h),v=j.countLines(c),k=window.getSelection();let E,R;if(k&&k.rangeCount>0){const T=k.getRangeAt(0);E=j.getCursorPosition(c,T),T.collapsed||(R=j.getSelectionInfo(T,E),E=void 0)}d.current?.update({wordCount:x,charCount:y,lineCount:v,cursorPosition:E,selectionInfo:R})};return c.addEventListener("input",m),c.addEventListener("selectionchange",m),document.addEventListener("selectionchange",m),m(),()=>{c.removeEventListener("input",m),c.removeEventListener("selectionchange",m),document.removeEventListener("selectionchange",m)}}}else d.current&&(d.current.destroy(),d.current=null);return()=>{d.current&&(d.current.destroy(),d.current=null)}},[t.statusbar.enabled,t.statusbar.position]);const f=t.toolbar.floating??!1,p=t.toolbar.position||"top",C=t.toolbar.sticky??!1;return o.jsx(le,{plugins:t.plugins,children:o.jsxs("div",{ref:b,id:t.id,"data-editora-editor":!0,className:`rte-editor ${t.className||""}`,dir:t.language.direction,style:{display:"flex",flexDirection:"column",height:"100%"},children:[p!=="bottom"&&o.jsx(H,{editor:r,position:p,sticky:C,floating:f}),o.jsx(V,{editor:r,defaultValue:t.defaultValue,value:t.value,onChange:t.onChange,pasteConfig:t.paste,contentConfig:t.content,securityConfig:t.security,performanceConfig:t.performance,autosaveConfig:t.autosave}),p==="bottom"&&o.jsx(H,{editor:r,position:p,sticky:C,floating:f}),o.jsx(ae,{editor:r,isEnabled:f}),t.statusbar.enabled&&o.jsx("div",{ref:w,className:"editora-statusbar-container",style:{order:t.statusbar.position==="top"?-1:1}})]})})},X=e=>o.jsx(se,{...e});function ce(e={}){const t=i.useRef(null),g=i.useRef(e.onCommand);return i.useEffect(()=>{g.current=e.onCommand}),i.useEffect(()=>{if(typeof window>"u"||e.enabled===!1)return;const u=new j.KeyboardShortcutManager(e);t.current=u;const s=b=>u.handleKeyDown(b,(w,r)=>{g.current&&g.current(w,r),typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(w,r)}),a=e.editorElement||document;return a&&a.addEventListener("keydown",s),()=>{a&&a.removeEventListener("keydown",s)}},[e.editorElement,e.enabled,e.shortcuts,e.customShortcuts]),{getShortcuts:()=>t.current?.getAllShortcuts()||[],getShortcutForCommand:u=>t.current?.getShortcutForCommand(u),getShortcutsHelp:()=>t.current?.getShortcutsHelp()||"",enable:()=>t.current?.enable(),disable:()=>t.current?.disable(),isEnabled:()=>t.current?.isEnabled()||!1}}exports.EditorContent=V;exports.EditoraEditor=X;exports.InlineMenu=P;exports.RichTextEditor=X;exports.Toolbar=H;exports.mergeConfig=G;exports.useKeyboardShortcuts=ce; | ||
| "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react/jsx-runtime"),c=require("react"),O=require("@editora/core"),ue=({isOpen:e,options:t,onSelect:f,onClose:l,anchorRef:r,className:o=""})=>{const h=c.useRef(null),[v,u]=c.useState(null),g=()=>{if(!e||!r.current)return;const d=r.current.getBoundingClientRect(),A=h.current?.getBoundingClientRect(),R=A?.width||120,I=A?.height||t.length*36,s=8,F=4,N=window.innerWidth,C=window.innerHeight;let p=d.bottom+F,a=d.left;a+R>N-s&&(a=N-R-s),a<s&&(a=s),p+I>C-s&&(p=d.top-I-F),p<s&&(p=s),u({top:p,left:a})};return c.useLayoutEffect(()=>{if(!e){u(null);return}g();const d=window.requestAnimationFrame(g);return()=>{window.cancelAnimationFrame(d)}},[e,t.length,r]),c.useEffect(()=>{if(!e)return;const d=()=>{g()};return window.addEventListener("resize",d),window.addEventListener("scroll",d,!0),()=>{window.removeEventListener("resize",d),window.removeEventListener("scroll",d,!0)}},[e,t.length,r]),c.useEffect(()=>{const d=R=>{h.current&&!h.current.contains(R.target)&&r.current&&!r.current.contains(R.target)&&l()},A=R=>{R.key==="Escape"&&l()};return e&&(document.addEventListener("mousedown",d),document.addEventListener("keydown",A)),()=>{document.removeEventListener("mousedown",d),document.removeEventListener("keydown",A)}},[e,l,r]),e?i.jsx("div",{ref:h,className:`rte-inline-menu ${o}`,style:{top:v?.top??-9999,left:v?.left??-9999,visibility:v?"visible":"hidden"},children:t.map(d=>i.jsx("div",{className:"rte-inline-menu-item",onClick:()=>{f(d.value),l()},children:d.label},d.value))}):null},$=e=>e.toLowerCase().replace(/[^a-z0-9]/g,""),Ee={undo:"undo",redo:"redo",bold:"toggleBold",italic:"toggleItalic",underline:"toggleUnderline",strikethrough:"toggleStrikethrough",textcolor:"openTextColorPicker",backgroundcolor:"openBackgroundColorPicker",fontsize:"setFontSize",increasefontsize:"increaseFontSize",decreasefontsize:"decreaseFontSize",heading:"setHeading",paragraph:"setHeading",textalignment:"setTextAlignment",direction:"setDirectionLTR",bullist:"toggleBulletList",numlist:"toggleOrderedList",checklist:"toggleChecklist",indent:"increaseIndent",outdent:"decreaseIndent",link:"openLinkDialog",image:"insertImage",video:"insertVideo",table:"insertTable",clearformatting:"clearFormatting"},xe=(e,t)=>{if(!Array.isArray(t)||t.length===0)return e;if(!t.every(u=>typeof u=="string"))return t;const l=new Map,r=new Map;e.forEach(u=>{l.set($(u.command||""),u),r.set($(u.label||""),u)});const o=t.flatMap(u=>u.split(/\s+/)).map(u=>u.trim()).filter(Boolean),h=[];let v=0;return o.forEach(u=>{if(u==="|"){v+=1,h.push({type:"separator",command:`__separator__${v}`,label:"|"});return}const g=$(u),d=Ee[g],A=l.get(g)||(d?l.get($(d)):void 0)||r.get(g)||e.find(R=>$(R.command||"").includes(g));A&&h.push(A)}),h.length>0?h:e},Q=({editor:e,position:t="top",sticky:f=!1,floating:l=!1,readonly:r=!1,showMoreOptions:o=!0,itemsOverride:h})=>{const[v,u]=c.useState(null),[g,d]=c.useState(null),[A,R]=c.useState(null),[I,s]=c.useState(!1),F=c.useRef(null),N=c.useRef(null),C=c.useRef({}),p=c.useRef([]),a=c.useRef(null),L=c.useRef(null),T=c.useRef(null),w=c.useMemo(()=>xe(e.pluginManager.getToolbarItems(),h),[e,h]),k=n=>{F.current=n,n&&!n.collapsed&&(N.current=n)},y=()=>a.current?.closest("[data-editora-editor]")?.querySelector(".rte-content")||null,M=()=>{if(typeof window>"u")return;const n=a.current?.closest("[data-editora-editor]");window.__editoraCommandEditorRoot=n||null},m=()=>{const n=y();if(!n)return null;const b=window.getSelection();if(!b||b.rangeCount===0)return null;const S=b.getRangeAt(0);return n.contains(S.commonAncestorContainer)?S.cloneRange():null},E=()=>{const n=m();n&&k(n)};c.useEffect(()=>{const n=()=>{E()};return document.addEventListener("selectionchange",n),()=>{document.removeEventListener("selectionchange",n)}},[]);const H=n=>["toggleBold","toggleItalic","toggleUnderline","toggleStrikethrough","openTextColorPicker","openBackgroundColorPicker","openLinkDialog","removeLink","toggleCode"].includes(n),B=(n=!1)=>{const b=y();if(!b)return!1;const S=window.getSelection();if(!S)return!1;const x=S.rangeCount>0&&b.contains(S.getRangeAt(0).commonAncestorContainer),j=n?N.current||F.current:F.current||N.current;if(n&&j&&j.collapsed)return!1;if(j&&b.contains(j.commonAncestorContainer))try{return b.focus({preventScroll:!0}),S.removeAllRanges(),S.addRange(j),!0}catch{}return x};c.useEffect(()=>{if(!o){R(null),s(!1),p.current=[];return}let n=null;const b=()=>{if(!a.current||!L.current)return;const j=a.current.clientWidth,G=16,Ce=40,ne=4,ye=Math.max(0,j-G-Ce-ne);let re=0,oe=0;const X=L.current.children;for(let U=0;U<X.length;U++){const J=X[U].getBoundingClientRect().width;J>0&&(p.current[U]=J);const ie=p.current[U]??J,le=(ie>0?ie:40)+ne;if(re+le<=ye)re+=le,oe++;else break}const ae=Math.max(1,Math.min(oe,X.length));R(U=>U===ae?U:ae)},S=()=>{n!==null&&cancelAnimationFrame(n),n=requestAnimationFrame(b)};p.current=[],S();const x=new ResizeObserver(()=>{S()});return a.current&&x.observe(a.current),L.current&&x.observe(L.current),()=>{n!==null&&cancelAnimationFrame(n),x.disconnect()}},[w.length,o]),c.useEffect(()=>{I&&A!==null&&A>=w.length&&s(!1)},[I,A,w.length]);const z=n=>(C.current[n]||(C.current[n]=c.createRef()),C.current[n]),D=(n,b)=>{if(r)return;M(),n==="addComment"||n==="toggleComments"||B(H(n));const j={toggleBold:"bold",toggleItalic:"italic",toggleUnderline:"underline"}[n];if(j){document.execCommand(j,!1),u(null);return}typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(n,b),u(null)},W=n=>{r||(E(),u(v===n?null:n))},_=n=>{r||(E(),d(g===n?null:n),u(null))},P=(n,b)=>{r||(B(),D(n,b),k(null),N.current=null,d(null))},q=(n,b)=>n&&n.startsWith("<svg")&&n.endsWith("</svg>")?i.jsx("span",{dangerouslySetInnerHTML:{__html:n}}):n&&n.length===1&&/^[BIUSH]$/.test(n)?i.jsx("span",{style:{fontWeight:"bold",fontSize:"14px",lineHeight:"1"},children:n}):n||"⚪",we={...f&&{position:"sticky",top:0,zIndex:100,backgroundColor:"#fff",boxShadow:"0 2px 4px rgba(0,0,0,0.1)"},...t==="bottom"&&{order:2}},ee=o&&A!==null&&A<w.length,pe=n=>{r||!n.target.closest(".rte-toolbar-button, .rte-toolbar-dropdown-item, .rte-toolbar-more-button")||(M(),E(),n.preventDefault())},te=n=>n.map((b,S)=>{const x=b.command||"";return i.jsx("div",{className:"rte-toolbar-item",style:{display:o&&A!==null&&S>=A?"none":"flex"},children:b.type==="separator"?i.jsx("div",{className:"rte-toolbar-separator","aria-hidden":"true"}):b.type==="dropdown"?i.jsxs("div",{className:"rte-toolbar-dropdown",children:[i.jsxs("button",{className:"rte-toolbar-button","data-command":x,"data-active":"false",onMouseDown:j=>{j.preventDefault(),E()},onClick:()=>W(x),disabled:r,children:[b.label," ▼"]}),v===x&&i.jsx("div",{className:"rte-toolbar-dropdown-menu",children:b.options?.map(j=>i.jsx("div",{className:"rte-toolbar-dropdown-item",onMouseDown:G=>G.preventDefault(),onClick:()=>D(x,j.value),children:j.label},j.value))})]}):b.type==="inline-menu"?i.jsx("button",{ref:z(x),className:"rte-toolbar-button","data-command":x,"data-active":"false",onMouseDown:j=>{j.preventDefault(),E()},onClick:()=>_(x),disabled:r,title:b.label,children:q(b.icon)}):b.type==="input"?i.jsx("input",{type:"text",className:`rte-toolbar-input ${b.label.toLowerCase().replace(/\s+/g,"-")}`,placeholder:b.placeholder,onChange:j=>D(x,j.target.value),disabled:r,onKeyDown:j=>{j.key==="Enter"&&D(x,j.target.value)},title:b.label}):b.type==="group"?i.jsx("div",{className:`rte-toolbar-group-button ${b.label.toLowerCase().replace(/\s+/g,"-")}`,title:`${b.label}`,children:i.jsx("div",{className:`rte-toolbar-group-items ${b.label.toLowerCase().replace(/\s+/g,"-")}`,children:te(b.items||[])})}):i.jsx("button",{className:"rte-toolbar-button","data-command":x,"data-active":"false",onMouseDown:j=>{j.preventDefault(),E()},onClick:()=>D(x),disabled:r,title:b.label,children:q(b.icon)})},S)});return i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"rte-toolbar-wrapper",style:we,onMouseDownCapture:pe,children:[i.jsxs("div",{className:"rte-toolbar",ref:a,children:[i.jsx("div",{className:"rte-toolbar-items-container",ref:L,style:o?void 0:{flexWrap:"wrap"},children:te(w)}),ee&&i.jsx("button",{ref:T,className:`rte-toolbar-more-button ${I?"active":""}`,onMouseDown:n=>{n.preventDefault(),E()},onClick:()=>s(!I),disabled:r,title:"Show more options","aria-label":"More toolbar options",children:"☰"})]}),ee&&i.jsx("div",{className:`rte-toolbar-expanded-row ${I?"show":""}`,children:w.map((n,b)=>{if(b<(A||0))return null;const S=n.command||"";return i.jsx("div",{className:"rte-toolbar-item",children:n.type==="separator"?i.jsx("div",{className:"rte-toolbar-separator","aria-hidden":"true"}):n.type==="dropdown"?i.jsxs("div",{className:"rte-toolbar-dropdown",children:[i.jsxs("button",{className:"rte-toolbar-button","data-command":S,"data-active":"false",onMouseDown:x=>{x.preventDefault(),E()},onClick:()=>W(S),disabled:r,children:[n.label," ▼"]}),v===S&&i.jsx("div",{className:"rte-toolbar-dropdown-menu",children:n.options?.map(x=>i.jsx("div",{className:"rte-toolbar-dropdown-item",onMouseDown:j=>j.preventDefault(),onClick:()=>D(S,x.value),children:x.label},x.value))})]}):n.type==="inline-menu"?i.jsx("button",{ref:z(S),className:"rte-toolbar-button","data-command":S,"data-active":"false",onMouseDown:x=>{x.preventDefault(),E()},onClick:()=>_(S),disabled:r,title:n.label,children:q(n.icon)}):n.type==="input"?i.jsx("input",{type:"text",className:"rte-toolbar-input",placeholder:n.placeholder,onChange:x=>D(S,x.target.value),disabled:r,onKeyDown:x=>{x.key==="Enter"&&D(S,x.target.value)},title:n.label}):i.jsx("button",{className:"rte-toolbar-button","data-command":S,"data-active":"false",onMouseDown:x=>{x.preventDefault(),E()},onClick:()=>D(S),disabled:r,title:n.label,children:q(n.icon)})},b)})})]}),w.map(n=>{if(n.type==="inline-menu"){const b=n.command||"";return i.jsx(ue,{isOpen:g===b,options:n.options||[],onSelect:S=>P(b,S),onClose:()=>d(null),anchorRef:z(b)},`menu-${b||"unknown"}`)}return null})]})};function ke(e,t){const f=c.useRef(),l=c.useRef("");return c.useEffect(()=>{if(!t?.enabled)return;const o=t.intervalMs||3e4,h=t.storageKey||"rte-autosave",v=t.provider||"localStorage",u=async()=>{const g=e();if(g!==l.current){if(l.current=g,v==="localStorage")try{localStorage.setItem(h,g),localStorage.setItem(`${h}-timestamp`,Date.now().toString()),console.log("[Autosave] Content saved to localStorage")}catch(d){console.error("[Autosave] Failed to save to localStorage:",d)}else if(v==="api"&&t.apiUrl)try{await fetch(t.apiUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:g,timestamp:Date.now()})}),console.log("[Autosave] Content saved to API")}catch(d){console.error("[Autosave] Failed to save to API:",d)}}};return f.current=setInterval(u,o),()=>{f.current&&clearInterval(f.current)}},[t?.enabled,t?.intervalMs,t?.storageKey,t?.provider,t?.apiUrl,e]),{restore:()=>{if(!t?.enabled)return null;const o=t.storageKey||"rte-autosave";if((t.provider||"localStorage")==="localStorage")try{const v=localStorage.getItem(o),u=localStorage.getItem(`${o}-timestamp`);if(v&&u)return console.log("[Autosave] Restored from localStorage, saved at:",new Date(parseInt(u))),v}catch(v){console.error("[Autosave] Failed to restore from localStorage:",v)}return null}}}const Se=["p","br","strong","em","u","s","strike","del","b","i","h1","h2","h3","h4","h5","h6","ul","ol","li","a","img","video","audio","table","thead","tbody","tr","th","td","blockquote","pre","code","span","div","sup","sub","hr"],Re={"*":["class","style","id","data-*"],a:["href","target","rel","title"],img:["src","alt","width","height","loading"],video:["src","controls","width","height","autoplay","loop","muted"],audio:["src","controls","autoplay","loop","muted"],table:["border","cellpadding","cellspacing"],td:["colspan","rowspan","align","valign"],th:["colspan","rowspan","align","valign"]};function de(e,t,f){if(t?.sanitize===!1)return e;const l=t?.allowedTags&&t.allowedTags.length>0?t.allowedTags:Se,o=!!t?.allowedAttributes&&Object.keys(t.allowedAttributes).length>0?t.allowedAttributes:Re,h=document.createElement("div");return h.innerHTML=e,fe(h,l,o),h.innerHTML}function fe(e,t,f){const l=Array.from(e.childNodes);for(const r of l)if(r.nodeType===Node.ELEMENT_NODE){const o=r,h=o.tagName.toLowerCase();if(!t.includes(h)){for(;o.firstChild;)e.insertBefore(o.firstChild,o);e.removeChild(o);continue}Le(o,f),fe(o,t,f)}else{if(r.nodeType===Node.TEXT_NODE)continue;e.removeChild(r)}}function Le(e,t){const f=e.tagName.toLowerCase(),l=Array.from(e.attributes),r=t[f]||[],o=t["*"]||[],h=[...r,...o];for(const v of l){const u=v.name.toLowerCase();let g=!1;h.includes(u)&&(g=!0);for(const d of h)if(d.endsWith("*")){const A=d.slice(0,-1);if(u.startsWith(A)){g=!0;break}}(u.startsWith("on")||u==="javascript:"||u==="href"&&v.value.trim().toLowerCase().startsWith("javascript:")||u==="src"&&v.value.trim().toLowerCase().startsWith("javascript:"))&&(g=!1),g||e.removeAttribute(v.name)}e.hasAttribute("href")&&(e.getAttribute("href")||"").trim().toLowerCase().startsWith("javascript:")&&e.removeAttribute("href"),e.hasAttribute("src")&&(e.getAttribute("src")||"").trim().toLowerCase().startsWith("javascript:")&&e.removeAttribute("src")}function Ae(e,t,f){return f?.sanitizeOnPaste===!1?e:de(e,t)}function Te(e,t,f){return f?.sanitizeOnInput===!1?e:de(e,t)}const V=e=>(e.textContent||"").replace(/\u200B/g,"").trim().length>0?!1:!e.querySelector("img, video, table, iframe, hr, pre, blockquote, ul, ol"),K=(e,t)=>{const l=!!t&&V(e);e.classList.toggle("rte-content-empty",l)},me=({editor:e,defaultValue:t,value:f,readonly:l=!1,placeholder:r,onChange:o,pasteConfig:h,contentConfig:v,securityConfig:u,performanceConfig:g,accessibilityConfig:d,autosaveConfig:A,contextMenuConfig:R,spellcheckConfig:I})=>{const s=c.useRef(null),F=f!==void 0,N=c.useRef(),{restore:C}=ke(()=>s.current?.innerHTML||"",A);c.useEffect(()=>{if(!s.current)return;const a=C(),L=a??f??t??"";L.trim()?s.current.innerHTML!==L&&(s.current.innerHTML=L):r?s.current.innerHTML="":s.current.innerHTML.trim()||(s.current.innerHTML="<p><br></p>"),K(s.current,r),a&&o&&o(a)},[]),c.useEffect(()=>{!s.current||!F||(f!==s.current.innerHTML&&(s.current.innerHTML=f),K(s.current,r))},[f,F]),c.useEffect(()=>{if(!s.current)return;const a=s.current;if(r){a.setAttribute("data-placeholder",r),V(a)&&(a.innerHTML=""),K(a,r);return}a.removeAttribute("data-placeholder"),K(a,r)},[r]),c.useEffect(()=>{if(!s.current)return;const a=s.current;if(d?.enableARIA!==!1){a.setAttribute("role","textbox"),a.setAttribute("aria-multiline","true"),a.setAttribute("aria-disabled",l?"true":"false");const T=r?.trim();T?a.setAttribute("aria-label",T):a.removeAttribute("aria-label")}else a.removeAttribute("role"),a.removeAttribute("aria-multiline"),a.removeAttribute("aria-label"),a.removeAttribute("aria-disabled")},[d?.enableARIA,r,l]),c.useEffect(()=>{if(!s.current)return;const a=()=>{if(!s.current||l)return;r&&V(s.current)&&(s.current.innerHTML="");let M=s.current.innerHTML;if(u?.sanitizeOnInput!==!1&&v?.sanitize!==!1&&(M=Te(M,v,u),M!==s.current.innerHTML)){const m=window.getSelection(),E=m&&m.rangeCount>0?m.getRangeAt(0):null;if(s.current.innerHTML=M,E&&m)try{m.removeAllRanges(),m.addRange(E)}catch{}}K(s.current,r),o&&(g?.debounceInputMs?(N.current&&clearTimeout(N.current),N.current=setTimeout(()=>{o(M)},g.debounceInputMs)):o(M))},L=M=>{if(l){M.preventDefault();return}M.preventDefault();let m=M.clipboardData?.getData("text/html");const E=M.clipboardData?.getData("text/plain"),H=!!m&&/class=["'][^"']*Mso|xmlns:w=|urn:schemas-microsoft-com:office/i.test(m);if(h?.clean||!h?.keepFormatting){E&&document.execCommand("insertText",!1,E);return}if(h?.convertWord===!1&&H){E&&document.execCommand("insertText",!1,E);return}if(m){u?.sanitizeOnPaste!==!1&&v?.sanitize!==!1&&(m=Ae(m,v,u));const B=window.getSelection();if(B&&B.rangeCount>0){const z=B.getRangeAt(0);z.deleteContents();const D=document.createElement("div");D.innerHTML=m;const W=document.createDocumentFragment();for(;D.firstChild;)W.appendChild(D.firstChild);z.insertNode(W),z.collapse(!1),B.removeAllRanges(),B.addRange(z)}}else E&&document.execCommand("insertText",!1,E)},T=M=>{const m=M.target;(m.tagName==="IMG"||m.tagName==="VIDEO")&&(m.style.resize="both",m.style.overflow="auto",m.style.display="inline-block")},w=M=>{R?.enabled===!1&&M.preventDefault()},k=()=>{s.current&&(r&&V(s.current)&&(s.current.innerHTML=""),K(s.current,r))},y=s.current;return y.addEventListener("input",a),y.addEventListener("paste",L),y.addEventListener("click",T),y.addEventListener("contextmenu",w),y.addEventListener("focus",k),y.addEventListener("blur",k),l||y.focus(),()=>{N.current&&clearTimeout(N.current),y.removeEventListener("input",a),y.removeEventListener("paste",L),y.removeEventListener("click",T),y.removeEventListener("contextmenu",w),y.removeEventListener("focus",k),y.removeEventListener("blur",k)}},[e,o,h,v,u,g,r,R,l]);const p=(I?.enabled??!1)&&(I?.provider??"browser")==="browser";return c.useEffect(()=>{if(!s.current||typeof window>"u"||l||d?.keyboardNavigation===!1)return;const a=new O.KeyboardShortcutManager,L=s.current,T=w=>{a.handleKeyDown(w,(k,y)=>{if(typeof window<"u"&&window.executeEditorCommand){const M=s.current?.closest("[data-editora-editor]");window.__editoraCommandEditorRoot=M||null,window.executeEditorCommand(k,y)}})};return L.addEventListener("keydown",T),()=>{L.removeEventListener("keydown",T)}},[d?.keyboardNavigation,l]),i.jsx("div",{ref:s,contentEditable:!l,suppressContentEditableWarning:!0,spellCheck:l?!1:p,tabIndex:d?.keyboardNavigation===!1?-1:0,"aria-keyshortcuts":d?.keyboardNavigation===!1?void 0:"Ctrl+B Ctrl+I Ctrl+U Ctrl+Z Ctrl+Y","data-viewport-only-scan":g?.viewportOnlyScan?"true":"false","data-a11y-checker":d?.checker?"true":"false","data-readonly":l?"true":"false",className:`rte-content ${l?"rte-content-readonly":""}`,style:{minHeight:"200px",maxHeight:"100%",padding:"16px",outline:"none",border:"1px solid #ddd",borderRadius:"0px 0px 4px 4px",fontSize:"14px",lineHeight:"1.5",overflow:"auto",flex:1,boxSizing:"border-box",wordWrap:"break-word",overflowWrap:"break-word"}})},Me=({editor:e,isEnabled:t,viewportOnlyScan:f=!0,readonly:l=!1})=>{const[r,o]=c.useState(!1),[h,v]=c.useState({top:0,left:0}),u=c.useRef(null),g=c.useRef(null),d=c.useRef(null),A=c.useRef(null),R=c.useRef(null);c.useEffect(()=>{if(!t||l){o(!1);return}R.current=u.current?.closest("[data-editora-editor]");const s=w=>{if(R.current)return R.current;const k=u.current?.closest("[data-editora-editor]");if(k)return R.current=k,k;const y=w?.commonAncestorContainer,m=(y?y.nodeType===Node.ELEMENT_NODE?y:y.parentElement:null)?.closest("[data-editora-editor]");return m?(R.current=m,m):null},F=w=>w&&w.querySelector(".rte-content, .editora-content")||null,N=w=>{if(!w.anchorNode||!w.focusNode)return!1;try{const k=document.createRange();return k.setStart(w.anchorNode,w.anchorOffset),k.setEnd(w.focusNode,w.focusOffset),k.collapsed}catch{return!1}},C=(w,k)=>{const y=Array.from(k.getClientRects()).filter(m=>m.width>0||m.height>0);return y.length===0?k.getBoundingClientRect():N(w)?y[0]:y[y.length-1]},p=()=>{A.current&&clearTimeout(A.current);const w=window.getSelection();if(!w||w.rangeCount===0){o(!1),d.current=null;return}const k=w.getRangeAt(0);if(k.collapsed){o(!1),d.current=null;return}const y=w.toString().trim(),M=s(k),m=F(M);if(!m||!m.contains(k.commonAncestorContainer)){o(!1),d.current=null;return}if(f){const E=m.getBoundingClientRect(),H=E.bottom>=0&&E.top<=window.innerHeight,B=document.activeElement===m||m.contains(document.activeElement);if(!H&&!B){o(!1),d.current=null;return}}if(y.length>0){const E=C(w,k),H=m.getBoundingClientRect(),B=300;if(E&&H){const z=Math.max(8,E.top-50);let D=E.left+E.width/2;const W=B/2,_=H.left,P=H.right;D-W<_&&(D=_+W+10),D+W>P&&(D=P-W-10),v({top:z,left:D}),o(!0),d.current=k.cloneRange()}}else o(!1),d.current=null},a=w=>{if(g.current&&!g.current.contains(w.target)){const k=s();window.getSelection(),F(k)?.contains(w.target)||(o(!1),d.current=null)}},L=w=>{w.key==="Escape"&&(o(!1),d.current=null)},T=F(s());return document.addEventListener("selectionchange",p),document.addEventListener("mousedown",a),document.addEventListener("keydown",L),T?.addEventListener("mouseup",p),T?.addEventListener("keyup",p),()=>{document.removeEventListener("selectionchange",p),document.removeEventListener("mousedown",a),document.removeEventListener("keydown",L),T?.removeEventListener("mouseup",p),T?.removeEventListener("keyup",p),A.current&&clearTimeout(A.current)}},[t,f,l]);const I=(s,F)=>{if(l||!d.current)return;typeof window<"u"&&(window.__editoraCommandEditorRoot=R.current||null);const N=R.current?.querySelector(".rte-content");N&&N.focus();const C=window.getSelection();if(C&&d.current)try{C.removeAllRanges(),C.addRange(d.current)}catch{}({toggleBold:()=>document.execCommand("bold",!1),toggleItalic:()=>document.execCommand("italic",!1),toggleUnderline:()=>document.execCommand("underline",!1),toggleStrikethrough:()=>document.execCommand("strikeThrough",!1),createLink:()=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand("openLinkDialog")},clearFormatting:()=>{document.execCommand("removeFormat",!1),document.execCommand("unlink",!1)},toggleCode:()=>{const a=window.getSelection();if(a&&a.rangeCount>0){const L=a.getRangeAt(0),T=document.createElement("code");L.surroundContents(T)}},setBlockType:()=>{if(F==="blockquote"){const a=window.getSelection();if(a&&a.rangeCount>0){const L=a.getRangeAt(0);(L.commonAncestorContainer.nodeType===Node.TEXT_NODE?L.commonAncestorContainer.parentElement:L.commonAncestorContainer)?.closest?.("blockquote")?document.execCommand("formatBlock",!1,"p"):document.execCommand("formatBlock",!1,"blockquote")}}else F&&document.execCommand("formatBlock",!1,F)}})[s]?.(),o(!1),d.current=null};return!t||l?i.jsx("span",{ref:u,style:{display:"none"},"aria-hidden":"true"}):i.jsxs(i.Fragment,{children:[i.jsx("span",{ref:u,style:{display:"none"},"aria-hidden":"true"}),r&&i.jsxs("div",{ref:g,className:"floating-toolbar",onMouseDown:s=>s.preventDefault(),style:{position:"fixed",top:`${h.top}px`,left:`${h.left}px`,transform:"translateX(-50%)",zIndex:1e4,display:"flex"},children:[i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("toggleBold"),title:"Bold (Ctrl+B)",children:i.jsx("strong",{children:"B"})}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("toggleItalic"),title:"Italic (Ctrl+I)",children:i.jsx("em",{children:"I"})}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("toggleUnderline"),title:"Underline (Ctrl+U)",children:i.jsx("u",{children:"U"})}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("toggleStrikethrough"),title:"Strikethrough",children:i.jsx("s",{children:"S"})}),i.jsx("div",{className:"floating-toolbar-separator"}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("clearFormatting"),title:"Clear Formatting",children:"⌫"}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("createLink"),title:"Insert Link",children:"🔗"}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("toggleCode"),title:"Code",children:"Code"}),i.jsx("div",{className:"floating-toolbar-separator"}),i.jsx("button",{className:"floating-toolbar-btn",onClick:()=>I("setBlockType","blockquote"),title:"Quote",children:"❝"})]})]})},je=({plugins:e,children:t})=>{const f=e.filter(r=>r.context?.provider);return f.length===0?i.jsx(i.Fragment,{children:t}):f.reduce((r,o)=>{const h=o.context.provider;return i.jsx(h,{children:r},o.name)},i.jsx(i.Fragment,{children:t}))},se=new Set,ce=new Set,Y=e=>!!e&&typeof e=="object"&&typeof e.name=="string",ge=e=>{const t=e?.pluginFactories;return{...(typeof window<"u"?window.EditoraReactPlugins:void 0)||{},...t||{}}},Ie=(e,t)=>{if(!Array.isArray(e))return[];const f=ge(t),l=[],r=[];if(e.forEach(o=>{if(Y(o)){l.push(o);return}if(typeof o!="string")return;const h=f[o];if(typeof h=="function")try{const v=h();if(Y(v)){l.push(v);return}}catch{}r.push(o)}),r.length>0){const o=r.slice().sort().join("|");se.has(o)||(se.add(o),console.warn(`[Editora React] Unresolved string plugin names: ${r.join(", ")}. Pass plugin instances or provide plugin factories via "pluginConfig.pluginFactories" or "window.EditoraReactPlugins".`))}return l},Ne=(e,t,f)=>{if(!t?.checker||e.some(o=>o?.name==="a11yChecker"))return e;const l=ge(f).a11yChecker;if(typeof l=="function")try{const o=l();if(Y(o))return[...e,o]}catch{}const r="accessibility.checker";return ce.has(r)||(ce.add(r),console.warn('[Editora React] accessibility.checker=true requires an "a11yChecker" plugin instance or factory.')),e},De={readonly:!1,placeholder:"",toolbar:{items:[],floating:!1,sticky:!1,showMoreOptions:!0},statusbar:{enabled:!1,position:"bottom"},menubar:{enabled:!1,items:[]},contextMenu:{enabled:!0},media:{uploadUrl:"",libraryUrl:"",maxFileSize:10*1024*1024,allowedTypes:["image/jpeg","image/png","image/gif","image/webp"],headers:{},withCredentials:!1},paste:{clean:!0,keepFormatting:!1,convertWord:!0},history:{maxSteps:100,debounceMs:300},language:{locale:"en",direction:"ltr"},spellcheck:{enabled:!1,provider:"browser",apiUrl:"",apiHeaders:{}},autosave:{enabled:!1,intervalMs:3e4,storageKey:"rte-autosave",provider:"localStorage",apiUrl:""},accessibility:{enableARIA:!0,keyboardNavigation:!0,checker:!1},performance:{debounceInputMs:100,viewportOnlyScan:!0},content:{allowedTags:[],allowedAttributes:{},sanitize:!0},security:{sanitizeOnPaste:!0,sanitizeOnInput:!0}};function be(e,t){const f={...e};for(const l in t){const r=t[l],o=f[l];r!==void 0&&(typeof r=="object"&&r!==null&&!Array.isArray(r)&&typeof o=="object"&&o!==null&&!Array.isArray(o)?f[l]=be(o,r):f[l]=r)}return f}function he(e){const t=be(De,{readonly:e.readonly,placeholder:e.placeholder,toolbar:e.toolbar,statusbar:e.statusbar,menubar:e.menubar,contextMenu:e.contextMenu,media:e.media,paste:e.paste,history:e.history,language:e.language,spellcheck:e.spellcheck,autosave:e.autosave,accessibility:e.accessibility,performance:e.performance,content:e.content,security:e.security});if(e.floatingToolbar!==void 0){const l=typeof e.floatingToolbar=="boolean"?e.floatingToolbar:e.floatingToolbar.enabled;t.toolbar={...t.toolbar,floating:l??t.toolbar.floating}}return e.mediaConfig&&(t.media={...t.media,uploadUrl:e.mediaConfig.uploadUrl||t.media.uploadUrl,libraryUrl:e.mediaConfig.libraryUrl||t.media.libraryUrl,maxFileSize:e.mediaConfig.maxFileSize||t.media.maxFileSize,allowedTypes:e.mediaConfig.allowedTypes||t.media.allowedTypes}),{...t,id:e.id,className:e.className,value:e.value,defaultValue:e.defaultValue,onChange:e.onChange,onInit:e.onInit,onDestroy:e.onDestroy,plugins:Ne(Ie(e.plugins,e.pluginConfig),e.accessibility,e.pluginConfig),pluginConfig:e.pluginConfig||{}}}const Z=new Map;typeof window<"u"&&(window.registerEditorCommand=(e,t)=>{Z.set(e,t)},window.executeEditorCommand=(e,t)=>{const f=Z.get(e);return f?f(t):(console.warn(`No handler registered for command: ${e}`),!1)});const Fe=e=>{const t=c.useMemo(()=>he(e),[e.id,e.className,e.value,e.defaultValue,e.readonly,e.placeholder,e.plugins,e.toolbar,e.menubar,e.contextMenu,e.media,e.paste,e.history,e.language,e.spellcheck,e.autosave,e.accessibility,e.performance,e.content,e.security,e.floatingToolbar,e.mediaConfig]),f=c.useRef(null),l=c.useRef(null),r=c.useRef(e.onInit),o=c.useRef(e.onDestroy),h=c.useRef(e.onChange),v=c.useRef(new Set),u=c.useRef(null),g=c.useRef(null),d=c.useRef(null);c.useEffect(()=>{r.current=e.onInit,o.current=e.onDestroy,h.current=e.onChange});const A=C=>{h.current?.(C),v.current.forEach(p=>{try{p(C)}catch(a){console.error("Editora onChange subscriber failed:",a)}})},R=c.useMemo(()=>{const C=new O.PluginManager;t.plugins.forEach(a=>{C.register(a),a.commands&&typeof window<"u"&&Object.entries(a.commands).forEach(([L,T])=>{Z.set(L,T)})});const p=new O.Editor(C);return f.current=p,p},[t.plugins]);c.useEffect(()=>{const C={getHTML:()=>u.current?.querySelector(".rte-content")?.innerHTML||"",setHTML:p=>{const a=u.current?.querySelector(".rte-content");a&&(a.innerHTML=p)},execCommand:(p,a)=>{typeof window<"u"&&window.executeEditorCommand&&(window.__editoraCommandEditorRoot=u.current||null,window.executeEditorCommand(p,a))},registerCommand:(p,a)=>{typeof window<"u"&&window.registerEditorCommand&&window.registerEditorCommand(p,a)},focus:()=>{u.current?.querySelector(".rte-content")?.focus()},blur:()=>{u.current?.querySelector(".rte-content")?.blur()},destroy:()=>{o.current&&o.current()},onChange:p=>(v.current.add(p),()=>{v.current.delete(p)}),getState:()=>({plugins:t.plugins,config:t}),toolbar:{items:R.toolbar?.items||[]}};return l.current=C,r.current&&r.current(C),()=>{v.current.clear(),o.current&&o.current()}},[]),c.useEffect(()=>{if(t.statusbar.enabled&&d.current&&u.current){g.current||(g.current=new O.StatusBar({enabled:!0,position:t.statusbar.position}),g.current.create(d.current));const C=u.current.querySelector(".rte-content");if(C){const p=()=>{const m=document.activeElement;return!!m&&(m===C||C.contains(m))},a=()=>{const m=C.getBoundingClientRect();return m.bottom>=0&&m.top<=window.innerHeight},L=()=>{const m=window.getSelection();if(!m||m.rangeCount===0)return null;const E=m.getRangeAt(0),H=E.commonAncestorContainer;return C.contains(H)?E:null},T=(m=!1)=>{if(t.performance.viewportOnlyScan!==!1&&!a()&&!p())return;const H=L(),B=!!H||p();if(m&&!B)return;const z=C.textContent||"",{words:D,chars:W}=O.calculateTextStats(z),_=O.countLines(C);let P,q;H&&(P=O.getCursorPosition(C,H),H.collapsed||(q=O.getSelectionInfo(H,P),P=void 0)),g.current?.update({wordCount:D,charCount:W,lineCount:_,cursorPosition:P,selectionInfo:q})},w=()=>T(),k=()=>T(!0),y=()=>T(),M=()=>T();return C.addEventListener("input",w),C.addEventListener("focus",y),C.addEventListener("blur",M),document.addEventListener("selectionchange",k),T(),()=>{C.removeEventListener("input",w),C.removeEventListener("focus",y),C.removeEventListener("blur",M),document.removeEventListener("selectionchange",k)}}}else g.current&&(g.current.destroy(),g.current=null);return()=>{g.current&&(g.current.destroy(),g.current=null)}},[t.statusbar.enabled,t.statusbar.position,t.performance.viewportOnlyScan]);const I=t.toolbar.floating??!1,s=t.toolbar.position||"top",F=t.toolbar.sticky??!1,N=t.toolbar.showMoreOptions??!0;return i.jsx(je,{plugins:t.plugins,children:i.jsxs("div",{ref:u,id:t.id,"data-editora-editor":!0,"data-readonly":t.readonly?"true":"false",className:`rte-editor ${t.className||""}`,lang:t.language.locale,dir:t.language.direction,style:{display:"flex",flexDirection:"column",height:"100%"},children:[s!=="bottom"&&i.jsx(Q,{editor:R,position:s,sticky:F,floating:I,readonly:t.readonly,showMoreOptions:N,itemsOverride:t.toolbar.items}),i.jsx(me,{editor:R,defaultValue:t.defaultValue,value:t.value,readonly:t.readonly,placeholder:t.placeholder,onChange:A,pasteConfig:t.paste,contentConfig:t.content,securityConfig:t.security,performanceConfig:t.performance,accessibilityConfig:t.accessibility,autosaveConfig:t.autosave,contextMenuConfig:t.contextMenu,spellcheckConfig:t.spellcheck}),s==="bottom"&&i.jsx(Q,{editor:R,position:s,sticky:F,floating:I,readonly:t.readonly,showMoreOptions:N,itemsOverride:t.toolbar.items}),i.jsx(Me,{editor:R,isEnabled:I,viewportOnlyScan:t.performance.viewportOnlyScan,readonly:t.readonly}),t.statusbar.enabled&&i.jsx("div",{ref:d,className:"editora-statusbar-container",style:{order:t.statusbar.position==="top"?-1:1}})]})})},ve=e=>i.jsx(Fe,{...e});function He(e={}){const t=c.useRef(null),f=c.useRef(e.onCommand);return c.useEffect(()=>{f.current=e.onCommand}),c.useEffect(()=>{if(typeof window>"u"||e.enabled===!1)return;const l=new O.KeyboardShortcutManager(e);t.current=l;const r=h=>l.handleKeyDown(h,(u,g)=>{f.current&&f.current(u,g),typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(u,g)}),o=e.editorElement||document;return o&&o.addEventListener("keydown",r),()=>{o&&o.removeEventListener("keydown",r)}},[e.editorElement,e.enabled,e.shortcuts,e.customShortcuts]),{getShortcuts:()=>t.current?.getAllShortcuts()||[],getShortcutForCommand:l=>t.current?.getShortcutForCommand(l),getShortcutsHelp:()=>t.current?.getShortcutsHelp()||"",enable:()=>t.current?.enable(),disable:()=>t.current?.disable(),isEnabled:()=>t.current?.isEnabled()||!1}}exports.EditorContent=me;exports.EditoraEditor=ve;exports.InlineMenu=ue;exports.RichTextEditor=ve;exports.Toolbar=Q;exports.mergeConfig=he;exports.useKeyboardShortcuts=He; |
+1018
-674
@@ -1,55 +0,56 @@ | ||
| import { jsx as l, jsxs as R, Fragment as B } from "react/jsx-runtime"; | ||
| import ee, { useRef as E, useState as N, useEffect as A, useMemo as j } from "react"; | ||
| import { KeyboardShortcutManager as _, PluginManager as te, Editor as ne, StatusBar as oe, calculateTextStats as re, countLines as ae, getCursorPosition as le, getSelectionInfo as ie } from "@editora/core"; | ||
| const ce = ({ | ||
| import { jsx as d, jsxs as U, Fragment as J } from "react/jsx-runtime"; | ||
| import ke, { useRef as T, useState as j, useLayoutEffect as Se, useEffect as z, useMemo as ee } from "react"; | ||
| import { KeyboardShortcutManager as ge, PluginManager as Le, Editor as Ae, StatusBar as xe, calculateTextStats as Te, countLines as Me, getCursorPosition as Re, getSelectionInfo as Ie } from "@editora/core"; | ||
| const Ne = ({ | ||
| isOpen: e, | ||
| options: t, | ||
| onSelect: m, | ||
| onClose: s, | ||
| anchorRef: i, | ||
| className: r = "" | ||
| onSelect: u, | ||
| onClose: i, | ||
| anchorRef: r, | ||
| className: o = "" | ||
| }) => { | ||
| const g = E(null), [d, h] = N({ top: 0, left: 0 }); | ||
| return A(() => { | ||
| if (e && i.current) { | ||
| const o = i.current.getBoundingClientRect(), u = 120, v = t.length * 36; | ||
| let C = o.bottom + 4, c = o.left; | ||
| const f = window.innerWidth, b = window.innerHeight; | ||
| c + u > f && (c = f - u - 8), C + v > b && (C = o.top - v - 4), h({ top: C, left: c }); | ||
| const b = T(null), [h, c] = j(null), m = () => { | ||
| if (!e || !r.current) return; | ||
| const s = r.current.getBoundingClientRect(), x = b.current?.getBoundingClientRect(), L = x?.width || 120, N = x?.height || t.length * 36, l = 8, B = 4, D = window.innerWidth, p = window.innerHeight; | ||
| let w = s.bottom + B, a = s.left; | ||
| a + L > D - l && (a = D - L - l), a < l && (a = l), w + N > p - l && (w = s.top - N - B), w < l && (w = l), c({ top: w, left: a }); | ||
| }; | ||
| return Se(() => { | ||
| if (!e) { | ||
| c(null); | ||
| return; | ||
| } | ||
| }, [e, i, t.length]), A(() => { | ||
| if (e && i.current && g.current) { | ||
| const o = i.current.getBoundingClientRect(), u = g.current.getBoundingClientRect(); | ||
| let v = o.bottom + 4, C = o.left; | ||
| const c = window.innerWidth, f = window.innerHeight; | ||
| C + u.width > c && (C = c - u.width - 8), v + u.height > f && (v = o.top - u.height - 4), h({ top: v, left: C }); | ||
| } | ||
| }, [e]), A(() => { | ||
| const o = (v) => { | ||
| g.current && !g.current.contains(v.target) && i.current && !i.current.contains(v.target) && s(); | ||
| }, u = (v) => { | ||
| v.key === "Escape" && s(); | ||
| m(); | ||
| const s = window.requestAnimationFrame(m); | ||
| return () => { | ||
| window.cancelAnimationFrame(s); | ||
| }; | ||
| return e && (document.addEventListener("mousedown", o), document.addEventListener("keydown", u)), () => { | ||
| document.removeEventListener("mousedown", o), document.removeEventListener("keydown", u); | ||
| }, [e, t.length, r]), z(() => { | ||
| if (!e) return; | ||
| const s = () => { | ||
| m(); | ||
| }; | ||
| }, [e, s, i]), e ? /* @__PURE__ */ l( | ||
| return window.addEventListener("resize", s), window.addEventListener("scroll", s, !0), () => { | ||
| window.removeEventListener("resize", s), window.removeEventListener("scroll", s, !0); | ||
| }; | ||
| }, [e, t.length, r]), z(() => { | ||
| const s = (L) => { | ||
| b.current && !b.current.contains(L.target) && r.current && !r.current.contains(L.target) && i(); | ||
| }, x = (L) => { | ||
| L.key === "Escape" && i(); | ||
| }; | ||
| return e && (document.addEventListener("mousedown", s), document.addEventListener("keydown", x)), () => { | ||
| document.removeEventListener("mousedown", s), document.removeEventListener("keydown", x); | ||
| }; | ||
| }, [e, i, r]), e ? /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| ref: g, | ||
| className: `rte-inline-menu ${r}`, | ||
| ref: b, | ||
| className: `rte-inline-menu ${o}`, | ||
| style: { | ||
| position: "fixed", | ||
| top: d.top, | ||
| left: d.left, | ||
| zIndex: 1e3, | ||
| background: "white", | ||
| border: "1px solid #ccc", | ||
| borderRadius: "4px", | ||
| boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)", | ||
| minWidth: "120px", | ||
| maxWidth: "200px", | ||
| pointerEvents: "auto" | ||
| top: h?.top ?? -9999, | ||
| left: h?.left ?? -9999, | ||
| visibility: h ? "visible" : "hidden" | ||
| }, | ||
| children: t.map((o) => /* @__PURE__ */ l( | ||
| children: t.map((s) => /* @__PURE__ */ d( | ||
| "div", | ||
@@ -59,88 +60,179 @@ { | ||
| onClick: () => { | ||
| m(o.value), s(); | ||
| u(s.value), i(); | ||
| }, | ||
| style: { | ||
| padding: "8px 12px", | ||
| cursor: "pointer", | ||
| borderBottom: "1px solid #f0f0f0", | ||
| fontSize: "14px", | ||
| whiteSpace: "nowrap", | ||
| overflow: "hidden", | ||
| textOverflow: "ellipsis" | ||
| }, | ||
| onMouseEnter: (u) => { | ||
| u.currentTarget.style.backgroundColor = "#f5f5f5"; | ||
| }, | ||
| onMouseLeave: (u) => { | ||
| u.currentTarget.style.backgroundColor = "transparent"; | ||
| }, | ||
| children: o.label | ||
| children: s.label | ||
| }, | ||
| o.value | ||
| s.value | ||
| )) | ||
| } | ||
| ) : null; | ||
| }, V = ({ | ||
| }, G = (e) => e.toLowerCase().replace(/[^a-z0-9]/g, ""), De = { | ||
| undo: "undo", | ||
| redo: "redo", | ||
| bold: "toggleBold", | ||
| italic: "toggleItalic", | ||
| underline: "toggleUnderline", | ||
| strikethrough: "toggleStrikethrough", | ||
| textcolor: "openTextColorPicker", | ||
| backgroundcolor: "openBackgroundColorPicker", | ||
| fontsize: "setFontSize", | ||
| increasefontsize: "increaseFontSize", | ||
| decreasefontsize: "decreaseFontSize", | ||
| heading: "setHeading", | ||
| paragraph: "setHeading", | ||
| textalignment: "setTextAlignment", | ||
| direction: "setDirectionLTR", | ||
| bullist: "toggleBulletList", | ||
| numlist: "toggleOrderedList", | ||
| checklist: "toggleChecklist", | ||
| indent: "increaseIndent", | ||
| outdent: "decreaseIndent", | ||
| link: "openLinkDialog", | ||
| image: "insertImage", | ||
| video: "insertVideo", | ||
| table: "insertTable", | ||
| clearformatting: "clearFormatting" | ||
| }, He = (e, t) => { | ||
| if (!Array.isArray(t) || t.length === 0) | ||
| return e; | ||
| if (!t.every((c) => typeof c == "string")) | ||
| return t; | ||
| const i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(); | ||
| e.forEach((c) => { | ||
| i.set(G(c.command || ""), c), r.set(G(c.label || ""), c); | ||
| }); | ||
| const o = t.flatMap((c) => c.split(/\s+/)).map((c) => c.trim()).filter(Boolean), b = []; | ||
| let h = 0; | ||
| return o.forEach((c) => { | ||
| if (c === "|") { | ||
| h += 1, b.push({ | ||
| type: "separator", | ||
| command: `__separator__${h}`, | ||
| label: "|" | ||
| }); | ||
| return; | ||
| } | ||
| const m = G(c), s = De[m], x = i.get(m) || (s ? i.get(G(s)) : void 0) || r.get(m) || e.find( | ||
| (L) => G(L.command || "").includes(m) | ||
| ); | ||
| x && b.push(x); | ||
| }), b.length > 0 ? b : e; | ||
| }, de = ({ | ||
| editor: e, | ||
| position: t = "top", | ||
| sticky: m = !1, | ||
| floating: s = !1 | ||
| sticky: u = !1, | ||
| floating: i = !1, | ||
| readonly: r = !1, | ||
| showMoreOptions: o = !0, | ||
| itemsOverride: b | ||
| }) => { | ||
| const [i, r] = N(null), [g, d] = N(null), [h, o] = N(null), [u, v] = N(null), [C, c] = N(!1), f = E({}), b = E(null), p = E(null), y = E(null), w = e.pluginManager.getToolbarItems(); | ||
| A(() => { | ||
| const [h, c] = j(null), [m, s] = j(null), [x, L] = j(null), [N, l] = j(!1), B = T(null), D = T(null), p = T({}), w = T([]), a = T(null), A = T(null), M = T(null), v = ee( | ||
| () => He(e.pluginManager.getToolbarItems(), b), | ||
| [e, b] | ||
| ), k = (n) => { | ||
| B.current = n, n && !n.collapsed && (D.current = n); | ||
| }, C = () => a.current?.closest("[data-editora-editor]")?.querySelector(".rte-content") || null, R = () => { | ||
| if (typeof window > "u") return; | ||
| const n = a.current?.closest("[data-editora-editor]"); | ||
| window.__editoraCommandEditorRoot = n || null; | ||
| }, f = () => { | ||
| const n = C(); | ||
| if (!n) return null; | ||
| const g = window.getSelection(); | ||
| if (!g || g.rangeCount === 0) return null; | ||
| const S = g.getRangeAt(0); | ||
| return n.contains(S.commonAncestorContainer) ? S.cloneRange() : null; | ||
| }, y = () => { | ||
| const n = f(); | ||
| n && k(n); | ||
| }; | ||
| z(() => { | ||
| const n = () => { | ||
| if (!b.current || !p.current) return; | ||
| const W = b.current.clientWidth, H = 16, Y = 40, U = 4, Z = W - H - Y - U; | ||
| let q = 0, P = 0; | ||
| const $ = p.current.children; | ||
| for (let z = 0; z < $.length; z++) { | ||
| const K = $[z].offsetWidth + U; | ||
| if (q + K <= Z) | ||
| q += K, P++; | ||
| y(); | ||
| }; | ||
| return document.addEventListener("selectionchange", n), () => { | ||
| document.removeEventListener("selectionchange", n); | ||
| }; | ||
| }, []); | ||
| const F = (n) => [ | ||
| "toggleBold", | ||
| "toggleItalic", | ||
| "toggleUnderline", | ||
| "toggleStrikethrough", | ||
| "openTextColorPicker", | ||
| "openBackgroundColorPicker", | ||
| "openLinkDialog", | ||
| "removeLink", | ||
| "toggleCode" | ||
| ].includes(n), W = (n = !1) => { | ||
| const g = C(); | ||
| if (!g) return !1; | ||
| const S = window.getSelection(); | ||
| if (!S) return !1; | ||
| const E = S.rangeCount > 0 && g.contains(S.getRangeAt(0).commonAncestorContainer), I = n ? D.current || B.current : B.current || D.current; | ||
| if (n && I && I.collapsed) | ||
| return !1; | ||
| if (I && g.contains(I.commonAncestorContainer)) | ||
| try { | ||
| return g.focus({ preventScroll: !0 }), S.removeAllRanges(), S.addRange(I), !0; | ||
| } catch { | ||
| } | ||
| return E; | ||
| }; | ||
| z(() => { | ||
| if (!o) { | ||
| L(null), l(!1), w.current = []; | ||
| return; | ||
| } | ||
| let n = null; | ||
| const g = () => { | ||
| if (!a.current || !A.current) return; | ||
| const I = a.current.clientWidth, Q = 16, ye = 40, ae = 4, Ee = Math.max(0, I - Q - ye - ae); | ||
| let ie = 0, le = 0; | ||
| const Y = A.current.children; | ||
| for (let q = 0; q < Y.length; q++) { | ||
| const Z = Y[q].getBoundingClientRect().width; | ||
| Z > 0 && (w.current[q] = Z); | ||
| const se = w.current[q] ?? Z, ue = (se > 0 ? se : 40) + ae; | ||
| if (ie + ue <= Ee) | ||
| ie += ue, le++; | ||
| else | ||
| break; | ||
| } | ||
| v(Math.max(1, P)); | ||
| }, a = requestAnimationFrame(() => { | ||
| n(); | ||
| }), k = new ResizeObserver(() => { | ||
| n(); | ||
| const ce = Math.max(1, Math.min(le, Y.length)); | ||
| L((q) => q === ce ? q : ce); | ||
| }, S = () => { | ||
| n !== null && cancelAnimationFrame(n), n = requestAnimationFrame(g); | ||
| }; | ||
| w.current = [], S(); | ||
| const E = new ResizeObserver(() => { | ||
| S(); | ||
| }); | ||
| b.current && k.observe(b.current); | ||
| const M = new MutationObserver(() => { | ||
| n(); | ||
| }); | ||
| return p.current && M.observe(p.current, { | ||
| childList: !0, | ||
| subtree: !0 | ||
| }), () => { | ||
| cancelAnimationFrame(a), k.disconnect(), M.disconnect(); | ||
| return a.current && E.observe(a.current), A.current && E.observe(A.current), () => { | ||
| n !== null && cancelAnimationFrame(n), E.disconnect(); | ||
| }; | ||
| }, [w.length]); | ||
| const S = (n) => (f.current[n] || (f.current[n] = ee.createRef()), f.current[n]), x = (n, a) => { | ||
| const k = b.current?.closest("[data-editora-editor]"), M = k?.querySelector(".rte-content"); | ||
| if (M && M.focus(), h && (n === "setTextAlignment" || n === "setFontFamily" || n === "setBlockType")) { | ||
| const H = window.getSelection(); | ||
| H && (H.removeAllRanges(), H.addRange(h)), o(null); | ||
| }, [v.length, o]), z(() => { | ||
| N && x !== null && x >= v.length && l(!1); | ||
| }, [N, x, v.length]); | ||
| const P = (n) => (p.current[n] || (p.current[n] = ke.createRef()), p.current[n]), H = (n, g) => { | ||
| if (r) return; | ||
| R(), n === "addComment" || n === "toggleComments" || W(F(n)); | ||
| const I = { | ||
| toggleBold: "bold", | ||
| toggleItalic: "italic", | ||
| toggleUnderline: "underline" | ||
| }[n]; | ||
| if (I) { | ||
| document.execCommand(I, !1), c(null); | ||
| return; | ||
| } | ||
| typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(n, a), r(null); | ||
| const W = k?.querySelector(".rte-content"); | ||
| W && W.focus(); | ||
| }, T = (n) => { | ||
| const a = window.getSelection(); | ||
| a && a.rangeCount > 0 && o(a.getRangeAt(0).cloneRange()), r(i === n ? null : n); | ||
| }, L = (n) => { | ||
| const a = window.getSelection(); | ||
| a && a.rangeCount > 0 && o(a.getRangeAt(0).cloneRange()), d(g === n ? null : n), r(null); | ||
| }, I = (n, a) => { | ||
| if (h) { | ||
| const k = window.getSelection(); | ||
| k && (k.removeAllRanges(), k.addRange(h)), o(null); | ||
| } | ||
| x(n, a), d(null); | ||
| }, D = (n, a) => n && n.startsWith("<svg") && n.endsWith("</svg>") ? /* @__PURE__ */ l("span", { dangerouslySetInnerHTML: { __html: n } }) : n && n.length === 1 && /^[BIUSH]$/.test(n) ? /* @__PURE__ */ l("span", { style: { fontWeight: "bold", fontSize: "14px", lineHeight: "1" }, children: n }) : n || "⚪"; | ||
| if (s) | ||
| return null; | ||
| const Q = { | ||
| ...m && { | ||
| typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(n, g), c(null); | ||
| }, O = (n) => { | ||
| r || (y(), c(h === n ? null : n)); | ||
| }, $ = (n) => { | ||
| r || (y(), s(m === n ? null : n), c(null)); | ||
| }, _ = (n, g) => { | ||
| r || (W(), H(n, g), k(null), D.current = null, s(null)); | ||
| }, V = (n, g) => n && n.startsWith("<svg") && n.endsWith("</svg>") ? /* @__PURE__ */ d("span", { dangerouslySetInnerHTML: { __html: n } }) : n && n.length === 1 && /^[BIUSH]$/.test(n) ? /* @__PURE__ */ d("span", { style: { fontWeight: "bold", fontSize: "14px", lineHeight: "1" }, children: n }) : n || "⚪", pe = { | ||
| ...u && { | ||
| position: "sticky", | ||
@@ -156,197 +248,260 @@ top: 0, | ||
| } | ||
| }, O = (n) => n.map((a, k) => /* @__PURE__ */ l( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-item", | ||
| style: { | ||
| display: u !== null && k >= u ? "none" : "flex" | ||
| }, | ||
| children: a.type === "dropdown" ? /* @__PURE__ */ R("div", { className: "rte-toolbar-dropdown", children: [ | ||
| /* @__PURE__ */ R( | ||
| }, re = o && x !== null && x < v.length, Ce = (n) => { | ||
| r || !n.target.closest(".rte-toolbar-button, .rte-toolbar-dropdown-item, .rte-toolbar-more-button") || (R(), y(), n.preventDefault()); | ||
| }, oe = (n) => n.map((g, S) => { | ||
| const E = g.command || ""; | ||
| return /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-item", | ||
| style: { | ||
| display: o && x !== null && S >= x ? "none" : "flex" | ||
| }, | ||
| children: g.type === "separator" ? /* @__PURE__ */ d("div", { className: "rte-toolbar-separator", "aria-hidden": "true" }) : g.type === "dropdown" ? /* @__PURE__ */ U("div", { className: "rte-toolbar-dropdown", children: [ | ||
| /* @__PURE__ */ U( | ||
| "button", | ||
| { | ||
| className: "rte-toolbar-button", | ||
| "data-command": E, | ||
| "data-active": "false", | ||
| onMouseDown: (I) => { | ||
| I.preventDefault(), y(); | ||
| }, | ||
| onClick: () => O(E), | ||
| disabled: r, | ||
| children: [ | ||
| g.label, | ||
| " ▼" | ||
| ] | ||
| } | ||
| ), | ||
| h === E && /* @__PURE__ */ d("div", { className: "rte-toolbar-dropdown-menu", children: g.options?.map((I) => /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-dropdown-item", | ||
| onMouseDown: (Q) => Q.preventDefault(), | ||
| onClick: () => H(E, I.value), | ||
| children: I.label | ||
| }, | ||
| I.value | ||
| )) }) | ||
| ] }) : g.type === "inline-menu" ? /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| ref: P(E), | ||
| className: "rte-toolbar-button", | ||
| "data-command": a.command, | ||
| "data-command": E, | ||
| "data-active": "false", | ||
| onClick: () => T(a.command), | ||
| children: [ | ||
| a.label, | ||
| " ▼" | ||
| ] | ||
| onMouseDown: (I) => { | ||
| I.preventDefault(), y(); | ||
| }, | ||
| onClick: () => $(E), | ||
| disabled: r, | ||
| title: g.label, | ||
| children: V(g.icon) | ||
| } | ||
| ), | ||
| i === a.command && /* @__PURE__ */ l("div", { className: "rte-toolbar-dropdown-menu", children: a.options?.map((M) => /* @__PURE__ */ l( | ||
| ) : g.type === "input" ? /* @__PURE__ */ d( | ||
| "input", | ||
| { | ||
| type: "text", | ||
| className: `rte-toolbar-input ${g.label.toLowerCase().replace(/\s+/g, "-")}`, | ||
| placeholder: g.placeholder, | ||
| onChange: (I) => H(E, I.target.value), | ||
| disabled: r, | ||
| onKeyDown: (I) => { | ||
| I.key === "Enter" && H( | ||
| E, | ||
| I.target.value | ||
| ); | ||
| }, | ||
| title: g.label | ||
| } | ||
| ) : g.type === "group" ? /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-dropdown-item", | ||
| onClick: () => x(a.command, M.value), | ||
| children: M.label | ||
| }, | ||
| M.value | ||
| )) }) | ||
| ] }) : a.type === "inline-menu" ? /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| ref: S(a.command), | ||
| className: "rte-toolbar-button", | ||
| "data-command": a.command, | ||
| "data-active": "false", | ||
| onClick: () => L(a.command), | ||
| title: a.label, | ||
| children: D(a.icon, a.command) | ||
| } | ||
| ) : a.type === "input" ? /* @__PURE__ */ l( | ||
| "input", | ||
| { | ||
| type: "text", | ||
| className: `rte-toolbar-input ${a.label.toLowerCase().replace(/\s+/g, "-")}`, | ||
| placeholder: a.placeholder, | ||
| onChange: (M) => x(a.command, M.target.value), | ||
| onKeyDown: (M) => { | ||
| M.key === "Enter" && x( | ||
| a.command, | ||
| M.target.value | ||
| ); | ||
| }, | ||
| title: a.label | ||
| } | ||
| ) : a.type === "group" ? /* @__PURE__ */ l( | ||
| "div", | ||
| { | ||
| className: `rte-toolbar-group-button ${a.label.toLowerCase().replace(/\s+/g, "-")}`, | ||
| title: `${a.label}`, | ||
| children: /* @__PURE__ */ l( | ||
| "div", | ||
| { | ||
| className: `rte-toolbar-group-items ${a.label.toLowerCase().replace(/\s+/g, "-")}`, | ||
| children: O(a.items || []) | ||
| } | ||
| ) | ||
| } | ||
| ) : /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "rte-toolbar-button", | ||
| "data-command": a.command, | ||
| "data-active": "false", | ||
| onClick: () => x(a.command), | ||
| title: a.label, | ||
| children: D(a.icon, a.command) | ||
| } | ||
| ) | ||
| }, | ||
| k | ||
| )); | ||
| return /* @__PURE__ */ R(B, { children: [ | ||
| /* @__PURE__ */ R("div", { className: "rte-toolbar-wrapper", style: Q, children: [ | ||
| /* @__PURE__ */ R("div", { className: "rte-toolbar", ref: b, children: [ | ||
| /* @__PURE__ */ l("div", { className: "rte-toolbar-items-container", ref: p, children: O(w) }), | ||
| u !== null && u < w.length && /* @__PURE__ */ l( | ||
| className: `rte-toolbar-group-button ${g.label.toLowerCase().replace(/\s+/g, "-")}`, | ||
| title: `${g.label}`, | ||
| children: /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| className: `rte-toolbar-group-items ${g.label.toLowerCase().replace(/\s+/g, "-")}`, | ||
| children: oe(g.items || []) | ||
| } | ||
| ) | ||
| } | ||
| ) : /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| ref: y, | ||
| className: `rte-toolbar-more-button ${C ? "active" : ""}`, | ||
| onClick: () => c(!C), | ||
| title: "Show more options", | ||
| "aria-label": "More toolbar options", | ||
| children: "☰" | ||
| className: "rte-toolbar-button", | ||
| "data-command": E, | ||
| "data-active": "false", | ||
| onMouseDown: (I) => { | ||
| I.preventDefault(), y(); | ||
| }, | ||
| onClick: () => H(E), | ||
| disabled: r, | ||
| title: g.label, | ||
| children: V(g.icon) | ||
| } | ||
| ) | ||
| ] }), | ||
| u !== null && u < w.length && /* @__PURE__ */ l( | ||
| "div", | ||
| { | ||
| className: `rte-toolbar-expanded-row ${C ? "show" : ""}`, | ||
| children: w.map( | ||
| (n, a) => a >= (u || 0) && /* @__PURE__ */ l("div", { className: "rte-toolbar-item", children: n.type === "dropdown" ? /* @__PURE__ */ R("div", { className: "rte-toolbar-dropdown", children: [ | ||
| /* @__PURE__ */ R( | ||
| "button", | ||
| { | ||
| className: "rte-toolbar-button", | ||
| "data-command": n.command, | ||
| "data-active": "false", | ||
| onClick: () => T(n.command), | ||
| children: [ | ||
| n.label, | ||
| " ▼" | ||
| ] | ||
| } | ||
| ), | ||
| i === n.command && /* @__PURE__ */ l("div", { className: "rte-toolbar-dropdown-menu", children: n.options?.map((k) => /* @__PURE__ */ l( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-dropdown-item", | ||
| onClick: () => x(n.command, k.value), | ||
| children: k.label | ||
| }, | ||
| k.value | ||
| )) }) | ||
| ] }) : n.type === "inline-menu" ? /* @__PURE__ */ l( | ||
| "button", | ||
| }, | ||
| S | ||
| ); | ||
| }); | ||
| return /* @__PURE__ */ U(J, { children: [ | ||
| /* @__PURE__ */ U( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-wrapper", | ||
| style: pe, | ||
| onMouseDownCapture: Ce, | ||
| children: [ | ||
| /* @__PURE__ */ U("div", { className: "rte-toolbar", ref: a, children: [ | ||
| /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| ref: S(n.command), | ||
| className: "rte-toolbar-button", | ||
| "data-command": n.command, | ||
| "data-active": "false", | ||
| onClick: () => L(n.command), | ||
| title: n.label, | ||
| children: D(n.icon, n.command) | ||
| className: "rte-toolbar-items-container", | ||
| ref: A, | ||
| style: o ? void 0 : { flexWrap: "wrap" }, | ||
| children: oe(v) | ||
| } | ||
| ) : n.type === "input" ? /* @__PURE__ */ l( | ||
| "input", | ||
| ), | ||
| re && /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| type: "text", | ||
| className: "rte-toolbar-input", | ||
| placeholder: n.placeholder, | ||
| onChange: (k) => x(n.command, k.target.value), | ||
| onKeyDown: (k) => { | ||
| k.key === "Enter" && x( | ||
| n.command, | ||
| k.target.value | ||
| ); | ||
| ref: M, | ||
| className: `rte-toolbar-more-button ${N ? "active" : ""}`, | ||
| onMouseDown: (n) => { | ||
| n.preventDefault(), y(); | ||
| }, | ||
| title: n.label | ||
| onClick: () => l(!N), | ||
| disabled: r, | ||
| title: "Show more options", | ||
| "aria-label": "More toolbar options", | ||
| children: "☰" | ||
| } | ||
| ) : /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "rte-toolbar-button", | ||
| "data-command": n.command, | ||
| "data-active": "false", | ||
| onClick: () => x(n.command), | ||
| title: n.label, | ||
| children: D(n.icon, n.command) | ||
| } | ||
| ) }, a) | ||
| ) | ||
| ] }), | ||
| re && /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| className: `rte-toolbar-expanded-row ${N ? "show" : ""}`, | ||
| children: v.map( | ||
| (n, g) => { | ||
| if (g < (x || 0)) return null; | ||
| const S = n.command || ""; | ||
| return /* @__PURE__ */ d("div", { className: "rte-toolbar-item", children: n.type === "separator" ? /* @__PURE__ */ d("div", { className: "rte-toolbar-separator", "aria-hidden": "true" }) : n.type === "dropdown" ? /* @__PURE__ */ U("div", { className: "rte-toolbar-dropdown", children: [ | ||
| /* @__PURE__ */ U( | ||
| "button", | ||
| { | ||
| className: "rte-toolbar-button", | ||
| "data-command": S, | ||
| "data-active": "false", | ||
| onMouseDown: (E) => { | ||
| E.preventDefault(), y(); | ||
| }, | ||
| onClick: () => O(S), | ||
| disabled: r, | ||
| children: [ | ||
| n.label, | ||
| " ▼" | ||
| ] | ||
| } | ||
| ), | ||
| h === S && /* @__PURE__ */ d("div", { className: "rte-toolbar-dropdown-menu", children: n.options?.map((E) => /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| className: "rte-toolbar-dropdown-item", | ||
| onMouseDown: (I) => I.preventDefault(), | ||
| onClick: () => H(S, E.value), | ||
| children: E.label | ||
| }, | ||
| E.value | ||
| )) }) | ||
| ] }) : n.type === "inline-menu" ? /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| ref: P(S), | ||
| className: "rte-toolbar-button", | ||
| "data-command": S, | ||
| "data-active": "false", | ||
| onMouseDown: (E) => { | ||
| E.preventDefault(), y(); | ||
| }, | ||
| onClick: () => $(S), | ||
| disabled: r, | ||
| title: n.label, | ||
| children: V(n.icon) | ||
| } | ||
| ) : n.type === "input" ? /* @__PURE__ */ d( | ||
| "input", | ||
| { | ||
| type: "text", | ||
| className: "rte-toolbar-input", | ||
| placeholder: n.placeholder, | ||
| onChange: (E) => H(S, E.target.value), | ||
| disabled: r, | ||
| onKeyDown: (E) => { | ||
| E.key === "Enter" && H( | ||
| S, | ||
| E.target.value | ||
| ); | ||
| }, | ||
| title: n.label | ||
| } | ||
| ) : /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "rte-toolbar-button", | ||
| "data-command": S, | ||
| "data-active": "false", | ||
| onMouseDown: (E) => { | ||
| E.preventDefault(), y(); | ||
| }, | ||
| onClick: () => H(S), | ||
| disabled: r, | ||
| title: n.label, | ||
| children: V(n.icon) | ||
| } | ||
| ) }, g); | ||
| } | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| ) | ||
| ] }), | ||
| w.map((n) => n.type === "inline-menu" ? /* @__PURE__ */ l( | ||
| ce, | ||
| { | ||
| isOpen: g === n.command, | ||
| options: n.options || [], | ||
| onSelect: (a) => I(n.command, a), | ||
| onClose: () => d(null), | ||
| anchorRef: S(n.command) | ||
| }, | ||
| `menu-${n.command}` | ||
| ) : null) | ||
| ] | ||
| } | ||
| ), | ||
| v.map((n) => { | ||
| if (n.type === "inline-menu") { | ||
| const g = n.command || ""; | ||
| return /* @__PURE__ */ d( | ||
| Ne, | ||
| { | ||
| isOpen: m === g, | ||
| options: n.options || [], | ||
| onSelect: (S) => _(g, S), | ||
| onClose: () => s(null), | ||
| anchorRef: P(g) | ||
| }, | ||
| `menu-${g || "unknown"}` | ||
| ); | ||
| } | ||
| return null; | ||
| }) | ||
| ] }); | ||
| }; | ||
| function se(e, t) { | ||
| const m = E(), s = E(""); | ||
| return A(() => { | ||
| function Be(e, t) { | ||
| const u = T(), i = T(""); | ||
| return z(() => { | ||
| if (!t?.enabled) return; | ||
| const r = t.intervalMs || 3e4, g = t.storageKey || "rte-autosave", d = t.provider || "localStorage", h = async () => { | ||
| const o = e(); | ||
| if (o !== s.current) { | ||
| if (s.current = o, d === "localStorage") | ||
| const o = t.intervalMs || 3e4, b = t.storageKey || "rte-autosave", h = t.provider || "localStorage", c = async () => { | ||
| const m = e(); | ||
| if (m !== i.current) { | ||
| if (i.current = m, h === "localStorage") | ||
| try { | ||
| localStorage.setItem(g, o), localStorage.setItem(`${g}-timestamp`, Date.now().toString()), console.log("[Autosave] Content saved to localStorage"); | ||
| } catch (u) { | ||
| console.error("[Autosave] Failed to save to localStorage:", u); | ||
| localStorage.setItem(b, m), localStorage.setItem(`${b}-timestamp`, Date.now().toString()), console.log("[Autosave] Content saved to localStorage"); | ||
| } catch (s) { | ||
| console.error("[Autosave] Failed to save to localStorage:", s); | ||
| } | ||
| else if (d === "api" && t.apiUrl) | ||
| else if (h === "api" && t.apiUrl) | ||
| try { | ||
@@ -358,22 +513,22 @@ await fetch(t.apiUrl, { | ||
| }, | ||
| body: JSON.stringify({ content: o, timestamp: Date.now() }) | ||
| body: JSON.stringify({ content: m, timestamp: Date.now() }) | ||
| }), console.log("[Autosave] Content saved to API"); | ||
| } catch (u) { | ||
| console.error("[Autosave] Failed to save to API:", u); | ||
| } catch (s) { | ||
| console.error("[Autosave] Failed to save to API:", s); | ||
| } | ||
| } | ||
| }; | ||
| return m.current = setInterval(h, r), () => { | ||
| m.current && clearInterval(m.current); | ||
| return u.current = setInterval(c, o), () => { | ||
| u.current && clearInterval(u.current); | ||
| }; | ||
| }, [t?.enabled, t?.intervalMs, t?.storageKey, t?.provider, t?.apiUrl, e]), { restore: () => { | ||
| if (!t?.enabled) return null; | ||
| const r = t.storageKey || "rte-autosave"; | ||
| const o = t.storageKey || "rte-autosave"; | ||
| if ((t.provider || "localStorage") === "localStorage") | ||
| try { | ||
| const d = localStorage.getItem(r), h = localStorage.getItem(`${r}-timestamp`); | ||
| if (d && h) | ||
| return console.log("[Autosave] Restored from localStorage, saved at:", new Date(parseInt(h))), d; | ||
| } catch (d) { | ||
| console.error("[Autosave] Failed to restore from localStorage:", d); | ||
| const h = localStorage.getItem(o), c = localStorage.getItem(`${o}-timestamp`); | ||
| if (h && c) | ||
| return console.log("[Autosave] Restored from localStorage, saved at:", new Date(parseInt(c))), h; | ||
| } catch (h) { | ||
| console.error("[Autosave] Failed to restore from localStorage:", h); | ||
| } | ||
@@ -383,3 +538,3 @@ return null; | ||
| } | ||
| const de = [ | ||
| const Fe = [ | ||
| "p", | ||
@@ -391,2 +546,4 @@ "br", | ||
| "s", | ||
| "strike", | ||
| "del", | ||
| "b", | ||
@@ -421,3 +578,3 @@ "i", | ||
| "hr" | ||
| ], ue = { | ||
| ], ze = { | ||
| "*": ["class", "style", "id", "data-*"], | ||
@@ -432,134 +589,184 @@ a: ["href", "target", "rel", "title"], | ||
| }; | ||
| function G(e, t, m) { | ||
| function be(e, t, u) { | ||
| if (t?.sanitize === !1) | ||
| return e; | ||
| const s = t?.allowedTags && t.allowedTags.length > 0 ? t.allowedTags : de, i = t?.allowedAttributes || ue, r = document.createElement("div"); | ||
| return r.innerHTML = e, X(r, s, i), r.innerHTML; | ||
| const i = t?.allowedTags && t.allowedTags.length > 0 ? t.allowedTags : Fe, o = !!t?.allowedAttributes && Object.keys(t.allowedAttributes).length > 0 ? t.allowedAttributes : ze, b = document.createElement("div"); | ||
| return b.innerHTML = e, he(b, i, o), b.innerHTML; | ||
| } | ||
| function X(e, t, m) { | ||
| const s = Array.from(e.childNodes); | ||
| for (const i of s) | ||
| if (i.nodeType === Node.ELEMENT_NODE) { | ||
| const r = i, g = r.tagName.toLowerCase(); | ||
| if (!t.includes(g)) { | ||
| for (; r.firstChild; ) | ||
| e.insertBefore(r.firstChild, r); | ||
| e.removeChild(r); | ||
| function he(e, t, u) { | ||
| const i = Array.from(e.childNodes); | ||
| for (const r of i) | ||
| if (r.nodeType === Node.ELEMENT_NODE) { | ||
| const o = r, b = o.tagName.toLowerCase(); | ||
| if (!t.includes(b)) { | ||
| for (; o.firstChild; ) | ||
| e.insertBefore(o.firstChild, o); | ||
| e.removeChild(o); | ||
| continue; | ||
| } | ||
| fe(r, m), X(r, t, m); | ||
| We(o, u), he(o, t, u); | ||
| } else { | ||
| if (i.nodeType === Node.TEXT_NODE) | ||
| if (r.nodeType === Node.TEXT_NODE) | ||
| continue; | ||
| e.removeChild(i); | ||
| e.removeChild(r); | ||
| } | ||
| } | ||
| function fe(e, t) { | ||
| const m = e.tagName.toLowerCase(), s = Array.from(e.attributes), i = t[m] || [], r = t["*"] || [], g = [...i, ...r]; | ||
| for (const d of s) { | ||
| const h = d.name.toLowerCase(); | ||
| let o = !1; | ||
| g.includes(h) && (o = !0); | ||
| for (const u of g) | ||
| if (u.endsWith("*")) { | ||
| const v = u.slice(0, -1); | ||
| if (h.startsWith(v)) { | ||
| o = !0; | ||
| function We(e, t) { | ||
| const u = e.tagName.toLowerCase(), i = Array.from(e.attributes), r = t[u] || [], o = t["*"] || [], b = [...r, ...o]; | ||
| for (const h of i) { | ||
| const c = h.name.toLowerCase(); | ||
| let m = !1; | ||
| b.includes(c) && (m = !0); | ||
| for (const s of b) | ||
| if (s.endsWith("*")) { | ||
| const x = s.slice(0, -1); | ||
| if (c.startsWith(x)) { | ||
| m = !0; | ||
| break; | ||
| } | ||
| } | ||
| (h.startsWith("on") || // Event handlers | ||
| h === "javascript:" || h === "href" && d.value.trim().toLowerCase().startsWith("javascript:") || h === "src" && d.value.trim().toLowerCase().startsWith("javascript:")) && (o = !1), o || e.removeAttribute(d.name); | ||
| (c.startsWith("on") || // Event handlers | ||
| c === "javascript:" || c === "href" && h.value.trim().toLowerCase().startsWith("javascript:") || c === "src" && h.value.trim().toLowerCase().startsWith("javascript:")) && (m = !1), m || e.removeAttribute(h.name); | ||
| } | ||
| e.hasAttribute("href") && (e.getAttribute("href") || "").trim().toLowerCase().startsWith("javascript:") && e.removeAttribute("href"), e.hasAttribute("src") && (e.getAttribute("src") || "").trim().toLowerCase().startsWith("javascript:") && e.removeAttribute("src"); | ||
| } | ||
| function me(e, t, m) { | ||
| return m?.sanitizeOnPaste === !1 ? e : G(e, t); | ||
| function Pe(e, t, u) { | ||
| return u?.sanitizeOnPaste === !1 ? e : be(e, t); | ||
| } | ||
| function ge(e, t, m) { | ||
| return m?.sanitizeOnInput === !1 ? e : G(e, t); | ||
| function Oe(e, t, u) { | ||
| return u?.sanitizeOnInput === !1 ? e : be(e, t); | ||
| } | ||
| const be = ({ | ||
| const X = (e) => (e.textContent || "").replace(/\u200B/g, "").trim().length > 0 ? !1 : !e.querySelector("img, video, table, iframe, hr, pre, blockquote, ul, ol"), K = (e, t) => { | ||
| const i = !!t && X(e); | ||
| e.classList.toggle("rte-content-empty", i); | ||
| }, Ue = ({ | ||
| editor: e, | ||
| defaultValue: t, | ||
| value: m, | ||
| onChange: s, | ||
| pasteConfig: i, | ||
| contentConfig: r, | ||
| securityConfig: g, | ||
| performanceConfig: d, | ||
| autosaveConfig: h | ||
| value: u, | ||
| readonly: i = !1, | ||
| placeholder: r, | ||
| onChange: o, | ||
| pasteConfig: b, | ||
| contentConfig: h, | ||
| securityConfig: c, | ||
| performanceConfig: m, | ||
| accessibilityConfig: s, | ||
| autosaveConfig: x, | ||
| contextMenuConfig: L, | ||
| spellcheckConfig: N | ||
| }) => { | ||
| const o = E(null), u = m !== void 0, v = E(), { restore: C } = se( | ||
| () => o.current?.innerHTML || "", | ||
| h | ||
| const l = T(null), B = u !== void 0, D = T(), { restore: p } = Be( | ||
| () => l.current?.innerHTML || "", | ||
| x | ||
| ); | ||
| return A(() => { | ||
| if (!o.current) return; | ||
| const c = C(), f = c || m || t; | ||
| f && o.current.innerHTML !== f && (o.current.innerHTML = f, c && s && s(c)); | ||
| }, []), A(() => { | ||
| !o.current || !u || m !== o.current.innerHTML && (o.current.innerHTML = m); | ||
| }, [m, u]), A(() => { | ||
| if (!o.current) return; | ||
| const c = () => { | ||
| if (!o.current || !s) return; | ||
| let y = o.current.innerHTML; | ||
| if (g?.sanitizeOnInput !== !1 && r?.sanitize !== !1 && (y = ge(y, r, g), y !== o.current.innerHTML)) { | ||
| const w = window.getSelection(), S = w && w.rangeCount > 0 ? w.getRangeAt(0) : null; | ||
| if (o.current.innerHTML = y, S && w) | ||
| z(() => { | ||
| if (!l.current) return; | ||
| const a = p(), A = a ?? u ?? t ?? ""; | ||
| A.trim() ? l.current.innerHTML !== A && (l.current.innerHTML = A) : r ? l.current.innerHTML = "" : l.current.innerHTML.trim() || (l.current.innerHTML = "<p><br></p>"), K(l.current, r), a && o && o(a); | ||
| }, []), z(() => { | ||
| !l.current || !B || (u !== l.current.innerHTML && (l.current.innerHTML = u), K(l.current, r)); | ||
| }, [u, B]), z(() => { | ||
| if (!l.current) return; | ||
| const a = l.current; | ||
| if (r) { | ||
| a.setAttribute("data-placeholder", r), X(a) && (a.innerHTML = ""), K(a, r); | ||
| return; | ||
| } | ||
| a.removeAttribute("data-placeholder"), K(a, r); | ||
| }, [r]), z(() => { | ||
| if (!l.current) return; | ||
| const a = l.current; | ||
| if (s?.enableARIA !== !1) { | ||
| a.setAttribute("role", "textbox"), a.setAttribute("aria-multiline", "true"), a.setAttribute("aria-disabled", i ? "true" : "false"); | ||
| const M = r?.trim(); | ||
| M ? a.setAttribute("aria-label", M) : a.removeAttribute("aria-label"); | ||
| } else | ||
| a.removeAttribute("role"), a.removeAttribute("aria-multiline"), a.removeAttribute("aria-label"), a.removeAttribute("aria-disabled"); | ||
| }, [s?.enableARIA, r, i]), z(() => { | ||
| if (!l.current) return; | ||
| const a = () => { | ||
| if (!l.current || i) return; | ||
| r && X(l.current) && (l.current.innerHTML = ""); | ||
| let R = l.current.innerHTML; | ||
| if (c?.sanitizeOnInput !== !1 && h?.sanitize !== !1 && (R = Oe(R, h, c), R !== l.current.innerHTML)) { | ||
| const f = window.getSelection(), y = f && f.rangeCount > 0 ? f.getRangeAt(0) : null; | ||
| if (l.current.innerHTML = R, y && f) | ||
| try { | ||
| w.removeAllRanges(), w.addRange(S); | ||
| f.removeAllRanges(), f.addRange(y); | ||
| } catch { | ||
| } | ||
| } | ||
| d?.debounceInputMs ? (v.current && clearTimeout(v.current), v.current = setTimeout(() => { | ||
| s(y); | ||
| }, d.debounceInputMs)) : s(y); | ||
| }, f = (y) => { | ||
| y.preventDefault(); | ||
| let w = y.clipboardData?.getData("text/html"); | ||
| const S = y.clipboardData?.getData("text/plain"); | ||
| if (i?.clean || !i?.keepFormatting) { | ||
| S && document.execCommand("insertText", !1, S); | ||
| K(l.current, r), o && (m?.debounceInputMs ? (D.current && clearTimeout(D.current), D.current = setTimeout(() => { | ||
| o(R); | ||
| }, m.debounceInputMs)) : o(R)); | ||
| }, A = (R) => { | ||
| if (i) { | ||
| R.preventDefault(); | ||
| return; | ||
| } | ||
| if (w) { | ||
| g?.sanitizeOnPaste !== !1 && r?.sanitize !== !1 && (w = me(w, r, g)); | ||
| const x = window.getSelection(); | ||
| if (x && x.rangeCount > 0) { | ||
| const T = x.getRangeAt(0); | ||
| T.deleteContents(); | ||
| const L = document.createElement("div"); | ||
| L.innerHTML = w; | ||
| const I = document.createDocumentFragment(); | ||
| for (; L.firstChild; ) | ||
| I.appendChild(L.firstChild); | ||
| T.insertNode(I), T.collapse(!1), x.removeAllRanges(), x.addRange(T); | ||
| R.preventDefault(); | ||
| let f = R.clipboardData?.getData("text/html"); | ||
| const y = R.clipboardData?.getData("text/plain"), F = !!f && /class=["'][^"']*Mso|xmlns:w=|urn:schemas-microsoft-com:office/i.test(f); | ||
| if (b?.clean || !b?.keepFormatting) { | ||
| y && document.execCommand("insertText", !1, y); | ||
| return; | ||
| } | ||
| if (b?.convertWord === !1 && F) { | ||
| y && document.execCommand("insertText", !1, y); | ||
| return; | ||
| } | ||
| if (f) { | ||
| c?.sanitizeOnPaste !== !1 && h?.sanitize !== !1 && (f = Pe(f, h, c)); | ||
| const W = window.getSelection(); | ||
| if (W && W.rangeCount > 0) { | ||
| const P = W.getRangeAt(0); | ||
| P.deleteContents(); | ||
| const H = document.createElement("div"); | ||
| H.innerHTML = f; | ||
| const O = document.createDocumentFragment(); | ||
| for (; H.firstChild; ) | ||
| O.appendChild(H.firstChild); | ||
| P.insertNode(O), P.collapse(!1), W.removeAllRanges(), W.addRange(P); | ||
| } | ||
| } else S && document.execCommand("insertText", !1, S); | ||
| }, b = (y) => { | ||
| const w = y.target; | ||
| (w.tagName === "IMG" || w.tagName === "VIDEO") && (w.style.resize = "both", w.style.overflow = "auto", w.style.display = "inline-block"); | ||
| }, p = o.current; | ||
| return p.addEventListener("input", c), p.addEventListener("paste", f), p.addEventListener("click", b), p.focus(), () => { | ||
| v.current && clearTimeout(v.current), p.removeEventListener("input", c), p.removeEventListener("paste", f), p.removeEventListener("click", b); | ||
| } else y && document.execCommand("insertText", !1, y); | ||
| }, M = (R) => { | ||
| const f = R.target; | ||
| (f.tagName === "IMG" || f.tagName === "VIDEO") && (f.style.resize = "both", f.style.overflow = "auto", f.style.display = "inline-block"); | ||
| }, v = (R) => { | ||
| L?.enabled === !1 && R.preventDefault(); | ||
| }, k = () => { | ||
| l.current && (r && X(l.current) && (l.current.innerHTML = ""), K(l.current, r)); | ||
| }, C = l.current; | ||
| return C.addEventListener("input", a), C.addEventListener("paste", A), C.addEventListener("click", M), C.addEventListener("contextmenu", v), C.addEventListener("focus", k), C.addEventListener("blur", k), i || C.focus(), () => { | ||
| D.current && clearTimeout(D.current), C.removeEventListener("input", a), C.removeEventListener("paste", A), C.removeEventListener("click", M), C.removeEventListener("contextmenu", v), C.removeEventListener("focus", k), C.removeEventListener("blur", k); | ||
| }; | ||
| }, [e, s, i, r, g, d]), A(() => { | ||
| if (!o.current || typeof window > "u") return; | ||
| const c = new _(), f = o.current, b = (p) => { | ||
| c.handleKeyDown(p, (y, w) => { | ||
| typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(y, w); | ||
| }, [e, o, b, h, c, m, r, L, i]); | ||
| const w = (N?.enabled ?? !1) && (N?.provider ?? "browser") === "browser"; | ||
| return z(() => { | ||
| if (!l.current || typeof window > "u" || i || s?.keyboardNavigation === !1) | ||
| return; | ||
| const a = new ge(), A = l.current, M = (v) => { | ||
| a.handleKeyDown(v, (k, C) => { | ||
| if (typeof window < "u" && window.executeEditorCommand) { | ||
| const R = l.current?.closest("[data-editora-editor]"); | ||
| window.__editoraCommandEditorRoot = R || null, window.executeEditorCommand(k, C); | ||
| } | ||
| }); | ||
| }; | ||
| return f.addEventListener("keydown", b), () => { | ||
| f.removeEventListener("keydown", b); | ||
| return A.addEventListener("keydown", M), () => { | ||
| A.removeEventListener("keydown", M); | ||
| }; | ||
| }, []), /* @__PURE__ */ l( | ||
| }, [s?.keyboardNavigation, i]), /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| ref: o, | ||
| contentEditable: !0, | ||
| ref: l, | ||
| contentEditable: !i, | ||
| suppressContentEditableWarning: !0, | ||
| className: "rte-content", | ||
| spellCheck: i ? !1 : w, | ||
| tabIndex: s?.keyboardNavigation === !1 ? -1 : 0, | ||
| "aria-keyshortcuts": s?.keyboardNavigation === !1 ? void 0 : "Ctrl+B Ctrl+I Ctrl+U Ctrl+Z Ctrl+Y", | ||
| "data-viewport-only-scan": m?.viewportOnlyScan ? "true" : "false", | ||
| "data-a11y-checker": s?.checker ? "true" : "false", | ||
| "data-readonly": i ? "true" : "false", | ||
| className: `rte-content ${i ? "rte-content-readonly" : ""}`, | ||
| style: { | ||
@@ -579,54 +786,94 @@ minHeight: "200px", | ||
| overflowWrap: "break-word" | ||
| }, | ||
| children: /* @__PURE__ */ l("p", { children: /* @__PURE__ */ l("br", {}) }) | ||
| } | ||
| } | ||
| ); | ||
| }, he = ({ | ||
| }, _e = ({ | ||
| editor: e, | ||
| isEnabled: t | ||
| isEnabled: t, | ||
| viewportOnlyScan: u = !0, | ||
| readonly: i = !1 | ||
| }) => { | ||
| const [m, s] = N(!1), [i, r] = N({ top: 0, left: 0 }), g = E(null), d = E(null), h = E(null), o = E(null); | ||
| A(() => { | ||
| if (!t) { | ||
| s(!1); | ||
| const [r, o] = j(!1), [b, h] = j({ top: 0, left: 0 }), c = T(null), m = T(null), s = T(null), x = T(null), L = T(null); | ||
| z(() => { | ||
| if (!t || i) { | ||
| o(!1); | ||
| return; | ||
| } | ||
| o.current = g.current?.closest("[data-editora-editor]"); | ||
| const v = () => { | ||
| h.current && clearTimeout(h.current); | ||
| const c = window.getSelection(); | ||
| if (!c || c.rangeCount === 0) { | ||
| s(!1), d.current = null; | ||
| L.current = c.current?.closest("[data-editora-editor]"); | ||
| const l = (v) => { | ||
| if (L.current) return L.current; | ||
| const k = c.current?.closest("[data-editora-editor]"); | ||
| if (k) | ||
| return L.current = k, k; | ||
| const C = v?.commonAncestorContainer, f = (C ? C.nodeType === Node.ELEMENT_NODE ? C : C.parentElement : null)?.closest("[data-editora-editor]"); | ||
| return f ? (L.current = f, f) : null; | ||
| }, B = (v) => v && v.querySelector(".rte-content, .editora-content") || null, D = (v) => { | ||
| if (!v.anchorNode || !v.focusNode) return !1; | ||
| try { | ||
| const k = document.createRange(); | ||
| return k.setStart(v.anchorNode, v.anchorOffset), k.setEnd(v.focusNode, v.focusOffset), k.collapsed; | ||
| } catch { | ||
| return !1; | ||
| } | ||
| }, p = (v, k) => { | ||
| const C = Array.from(k.getClientRects()).filter((f) => f.width > 0 || f.height > 0); | ||
| return C.length === 0 ? k.getBoundingClientRect() : D(v) ? C[0] : C[C.length - 1]; | ||
| }, w = () => { | ||
| x.current && clearTimeout(x.current); | ||
| const v = window.getSelection(); | ||
| if (!v || v.rangeCount === 0) { | ||
| o(!1), s.current = null; | ||
| return; | ||
| } | ||
| const f = c.getRangeAt(0), b = c.toString().trim(), p = o.current?.querySelector(".rte-content"); | ||
| if (!p || !p.contains(f.commonAncestorContainer)) { | ||
| s(!1), d.current = null; | ||
| const k = v.getRangeAt(0); | ||
| if (k.collapsed) { | ||
| o(!1), s.current = null; | ||
| return; | ||
| } | ||
| if (b.length > 0) { | ||
| const y = f.getBoundingClientRect(), w = p.getBoundingClientRect(), S = 300; | ||
| if (y && w) { | ||
| const x = y.top - 50; | ||
| let T = y.left + y.width / 2; | ||
| const L = S / 2, I = w.left, D = w.right; | ||
| T - L < I && (T = I + L + 10), T + L > D && (T = D - L - 10), r({ top: x, left: T }), h.current = setTimeout(() => { | ||
| s(!0), d.current = f.cloneRange(); | ||
| }, 300); | ||
| const C = v.toString().trim(), R = l(k), f = B(R); | ||
| if (!f || !f.contains(k.commonAncestorContainer)) { | ||
| o(!1), s.current = null; | ||
| return; | ||
| } | ||
| if (u) { | ||
| const y = f.getBoundingClientRect(), F = y.bottom >= 0 && y.top <= window.innerHeight, W = document.activeElement === f || f.contains(document.activeElement); | ||
| if (!F && !W) { | ||
| o(!1), s.current = null; | ||
| return; | ||
| } | ||
| } | ||
| if (C.length > 0) { | ||
| const y = p(v, k), F = f.getBoundingClientRect(), W = 300; | ||
| if (y && F) { | ||
| const P = Math.max(8, y.top - 50); | ||
| let H = y.left + y.width / 2; | ||
| const O = W / 2, $ = F.left, _ = F.right; | ||
| H - O < $ && (H = $ + O + 10), H + O > _ && (H = _ - O - 10), h({ top: P, left: H }), o(!0), s.current = k.cloneRange(); | ||
| } | ||
| } else | ||
| s(!1), d.current = null; | ||
| }, C = (c) => { | ||
| g.current && !g.current.contains(c.target) && (window.getSelection(), o.current?.querySelector(".rte-content")?.contains(c.target) || (s(!1), d.current = null)); | ||
| o(!1), s.current = null; | ||
| }, a = (v) => { | ||
| if (m.current && !m.current.contains(v.target)) { | ||
| const k = l(); | ||
| window.getSelection(), B(k)?.contains(v.target) || (o(!1), s.current = null); | ||
| } | ||
| }, A = (v) => { | ||
| v.key === "Escape" && (o(!1), s.current = null); | ||
| }, M = B(l()); | ||
| return document.addEventListener("selectionchange", w), document.addEventListener("mousedown", a), document.addEventListener("keydown", A), M?.addEventListener("mouseup", w), M?.addEventListener("keyup", w), () => { | ||
| document.removeEventListener("selectionchange", w), document.removeEventListener("mousedown", a), document.removeEventListener("keydown", A), M?.removeEventListener("mouseup", w), M?.removeEventListener("keyup", w), x.current && clearTimeout(x.current); | ||
| }; | ||
| return document.addEventListener("selectionchange", v), document.addEventListener("mousedown", C), document.addEventListener("keydown", (c) => { | ||
| c.key === "Escape" && (s(!1), d.current = null); | ||
| }), () => { | ||
| document.removeEventListener("selectionchange", v), document.removeEventListener("mousedown", C), h.current && clearTimeout(h.current); | ||
| }; | ||
| }, [t]); | ||
| const u = (v, C) => { | ||
| if (!d.current) return; | ||
| const c = o.current?.querySelector(".rte-content"); | ||
| c && c.focus(), { | ||
| }, [t, u, i]); | ||
| const N = (l, B) => { | ||
| if (i || !s.current) return; | ||
| typeof window < "u" && (window.__editoraCommandEditorRoot = L.current || null); | ||
| const D = L.current?.querySelector(".rte-content"); | ||
| D && D.focus(); | ||
| const p = window.getSelection(); | ||
| if (p && s.current) | ||
| try { | ||
| p.removeAllRanges(), p.addRange(s.current); | ||
| } catch { | ||
| } | ||
| ({ | ||
| toggleBold: () => document.execCommand("bold", !1), | ||
@@ -643,134 +890,183 @@ toggleItalic: () => document.execCommand("italic", !1), | ||
| toggleCode: () => { | ||
| const b = window.getSelection(); | ||
| if (b && b.rangeCount > 0) { | ||
| const p = b.getRangeAt(0), y = document.createElement("code"); | ||
| p.surroundContents(y); | ||
| const a = window.getSelection(); | ||
| if (a && a.rangeCount > 0) { | ||
| const A = a.getRangeAt(0), M = document.createElement("code"); | ||
| A.surroundContents(M); | ||
| } | ||
| }, | ||
| setBlockType: () => { | ||
| if (C === "blockquote") { | ||
| const b = window.getSelection(); | ||
| if (b && b.rangeCount > 0) { | ||
| const p = b.getRangeAt(0); | ||
| (p.commonAncestorContainer.nodeType === Node.TEXT_NODE ? p.commonAncestorContainer.parentElement : p.commonAncestorContainer)?.closest?.("blockquote") ? document.execCommand("formatBlock", !1, "p") : document.execCommand("formatBlock", !1, "blockquote"); | ||
| if (B === "blockquote") { | ||
| const a = window.getSelection(); | ||
| if (a && a.rangeCount > 0) { | ||
| const A = a.getRangeAt(0); | ||
| (A.commonAncestorContainer.nodeType === Node.TEXT_NODE ? A.commonAncestorContainer.parentElement : A.commonAncestorContainer)?.closest?.("blockquote") ? document.execCommand("formatBlock", !1, "p") : document.execCommand("formatBlock", !1, "blockquote"); | ||
| } | ||
| } else C && document.execCommand("formatBlock", !1, C); | ||
| } else B && document.execCommand("formatBlock", !1, B); | ||
| } | ||
| }[v]?.(), s(!1), d.current = null, c && c.focus(); | ||
| })[l]?.(), o(!1), s.current = null; | ||
| }; | ||
| return !t || !m ? null : /* @__PURE__ */ R( | ||
| "div", | ||
| { | ||
| ref: g, | ||
| className: "floating-toolbar", | ||
| style: { | ||
| position: "fixed", | ||
| top: `${i.top}px`, | ||
| left: `${i.left}px`, | ||
| transform: "translateX(-50%)", | ||
| zIndex: 1e3, | ||
| background: "white", | ||
| border: "1px solid #e1e5e9", | ||
| borderRadius: "6px", | ||
| boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)", | ||
| padding: "6px", | ||
| display: "flex", | ||
| gap: "4px", | ||
| alignItems: "center" | ||
| }, | ||
| children: [ | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("toggleBold"), | ||
| title: "Bold (Ctrl+B)", | ||
| children: /* @__PURE__ */ l("strong", { children: "B" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("toggleItalic"), | ||
| title: "Italic (Ctrl+I)", | ||
| children: /* @__PURE__ */ l("em", { children: "I" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("toggleUnderline"), | ||
| title: "Underline (Ctrl+U)", | ||
| children: /* @__PURE__ */ l("u", { children: "U" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("toggleStrikethrough"), | ||
| title: "Strikethrough", | ||
| children: /* @__PURE__ */ l("s", { children: "S" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l("div", { className: "floating-toolbar-separator" }), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("clearFormatting"), | ||
| title: "Clear Formatting", | ||
| children: "⌫" | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("createLink"), | ||
| title: "Insert Link", | ||
| children: "🔗" | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("toggleCode"), | ||
| title: "Code", | ||
| children: "Code" | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l("div", { className: "floating-toolbar-separator" }), | ||
| /* @__PURE__ */ l( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => u("setBlockType", "blockquote"), | ||
| title: "Quote", | ||
| children: "❝" | ||
| } | ||
| ) | ||
| ] | ||
| } | ||
| ); | ||
| }, we = ({ | ||
| return !t || i ? /* @__PURE__ */ d("span", { ref: c, style: { display: "none" }, "aria-hidden": "true" }) : /* @__PURE__ */ U(J, { children: [ | ||
| /* @__PURE__ */ d("span", { ref: c, style: { display: "none" }, "aria-hidden": "true" }), | ||
| r && /* @__PURE__ */ U( | ||
| "div", | ||
| { | ||
| ref: m, | ||
| className: "floating-toolbar", | ||
| onMouseDown: (l) => l.preventDefault(), | ||
| style: { | ||
| position: "fixed", | ||
| top: `${b.top}px`, | ||
| left: `${b.left}px`, | ||
| transform: "translateX(-50%)", | ||
| zIndex: 1e4, | ||
| display: "flex" | ||
| }, | ||
| children: [ | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("toggleBold"), | ||
| title: "Bold (Ctrl+B)", | ||
| children: /* @__PURE__ */ d("strong", { children: "B" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("toggleItalic"), | ||
| title: "Italic (Ctrl+I)", | ||
| children: /* @__PURE__ */ d("em", { children: "I" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("toggleUnderline"), | ||
| title: "Underline (Ctrl+U)", | ||
| children: /* @__PURE__ */ d("u", { children: "U" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("toggleStrikethrough"), | ||
| title: "Strikethrough", | ||
| children: /* @__PURE__ */ d("s", { children: "S" }) | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d("div", { className: "floating-toolbar-separator" }), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("clearFormatting"), | ||
| title: "Clear Formatting", | ||
| children: "⌫" | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("createLink"), | ||
| title: "Insert Link", | ||
| children: "🔗" | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("toggleCode"), | ||
| title: "Code", | ||
| children: "Code" | ||
| } | ||
| ), | ||
| /* @__PURE__ */ d("div", { className: "floating-toolbar-separator" }), | ||
| /* @__PURE__ */ d( | ||
| "button", | ||
| { | ||
| className: "floating-toolbar-btn", | ||
| onClick: () => N("setBlockType", "blockquote"), | ||
| title: "Quote", | ||
| children: "❝" | ||
| } | ||
| ) | ||
| ] | ||
| } | ||
| ) | ||
| ] }); | ||
| }, qe = ({ | ||
| plugins: e, | ||
| children: t | ||
| }) => { | ||
| const m = e.filter((i) => i.context?.provider); | ||
| return m.length === 0 ? /* @__PURE__ */ l(B, { children: t }) : m.reduce( | ||
| (i, r) => { | ||
| const g = r.context.provider; | ||
| return /* @__PURE__ */ l(g, { children: i }, r.name); | ||
| const u = e.filter((r) => r.context?.provider); | ||
| return u.length === 0 ? /* @__PURE__ */ d(J, { children: t }) : u.reduce( | ||
| (r, o) => { | ||
| const b = o.context.provider; | ||
| return /* @__PURE__ */ d(b, { children: r }, o.name); | ||
| }, | ||
| /* @__PURE__ */ l(B, { children: t }) | ||
| /* @__PURE__ */ d(J, { children: t }) | ||
| ); | ||
| }, ve = { | ||
| }, fe = /* @__PURE__ */ new Set(), me = /* @__PURE__ */ new Set(), te = (e) => !!e && typeof e == "object" && typeof e.name == "string", ve = (e) => { | ||
| const t = e?.pluginFactories; | ||
| return { | ||
| ...(typeof window < "u" ? window.EditoraReactPlugins : void 0) || {}, | ||
| ...t || {} | ||
| }; | ||
| }, $e = (e, t) => { | ||
| if (!Array.isArray(e)) return []; | ||
| const u = ve(t), i = [], r = []; | ||
| if (e.forEach((o) => { | ||
| if (te(o)) { | ||
| i.push(o); | ||
| return; | ||
| } | ||
| if (typeof o != "string") return; | ||
| const b = u[o]; | ||
| if (typeof b == "function") | ||
| try { | ||
| const h = b(); | ||
| if (te(h)) { | ||
| i.push(h); | ||
| return; | ||
| } | ||
| } catch { | ||
| } | ||
| r.push(o); | ||
| }), r.length > 0) { | ||
| const o = r.slice().sort().join("|"); | ||
| fe.has(o) || (fe.add(o), console.warn( | ||
| `[Editora React] Unresolved string plugin names: ${r.join( | ||
| ", " | ||
| )}. Pass plugin instances or provide plugin factories via "pluginConfig.pluginFactories" or "window.EditoraReactPlugins".` | ||
| )); | ||
| } | ||
| return i; | ||
| }, Ve = (e, t, u) => { | ||
| if (!t?.checker || e.some((o) => o?.name === "a11yChecker")) return e; | ||
| const i = ve(u).a11yChecker; | ||
| if (typeof i == "function") | ||
| try { | ||
| const o = i(); | ||
| if (te(o)) | ||
| return [...e, o]; | ||
| } catch { | ||
| } | ||
| const r = "accessibility.checker"; | ||
| return me.has(r) || (me.add(r), console.warn( | ||
| '[Editora React] accessibility.checker=true requires an "a11yChecker" plugin instance or factory.' | ||
| )), e; | ||
| }, je = { | ||
| readonly: !1, | ||
| placeholder: "", | ||
| toolbar: { | ||
| items: [], | ||
| floating: !1, | ||
| sticky: !1 | ||
| sticky: !1, | ||
| showMoreOptions: !0 | ||
| }, | ||
@@ -843,12 +1139,14 @@ statusbar: { | ||
| }; | ||
| function J(e, t) { | ||
| const m = { ...e }; | ||
| for (const s in t) { | ||
| const i = t[s], r = m[s]; | ||
| i !== void 0 && (typeof i == "object" && i !== null && !Array.isArray(i) && typeof r == "object" && r !== null && !Array.isArray(r) ? m[s] = J(r, i) : m[s] = i); | ||
| function we(e, t) { | ||
| const u = { ...e }; | ||
| for (const i in t) { | ||
| const r = t[i], o = u[i]; | ||
| r !== void 0 && (typeof r == "object" && r !== null && !Array.isArray(r) && typeof o == "object" && o !== null && !Array.isArray(o) ? u[i] = we(o, r) : u[i] = r); | ||
| } | ||
| return m; | ||
| return u; | ||
| } | ||
| function pe(e) { | ||
| const t = J(ve, { | ||
| function Ke(e) { | ||
| const t = we(je, { | ||
| readonly: e.readonly, | ||
| placeholder: e.placeholder, | ||
| toolbar: e.toolbar, | ||
@@ -869,6 +1167,10 @@ statusbar: e.statusbar, | ||
| }); | ||
| return e.floatingToolbar !== void 0 && (t.toolbar = { | ||
| ...t.toolbar, | ||
| floating: e.floatingToolbar.enabled ?? t.toolbar.floating | ||
| }), e.mediaConfig && (t.media = { | ||
| if (e.floatingToolbar !== void 0) { | ||
| const i = typeof e.floatingToolbar == "boolean" ? e.floatingToolbar : e.floatingToolbar.enabled; | ||
| t.toolbar = { | ||
| ...t.toolbar, | ||
| floating: i ?? t.toolbar.floating | ||
| }; | ||
| } | ||
| return e.mediaConfig && (t.media = { | ||
| ...t.media, | ||
@@ -888,15 +1190,19 @@ uploadUrl: e.mediaConfig.uploadUrl || t.media.uploadUrl, | ||
| onDestroy: e.onDestroy, | ||
| plugins: Array.isArray(e.plugins) ? e.plugins.filter((s) => typeof s != "string") : [], | ||
| plugins: Ve( | ||
| $e(e.plugins, e.pluginConfig), | ||
| e.accessibility, | ||
| e.pluginConfig | ||
| ), | ||
| pluginConfig: e.pluginConfig || {} | ||
| }; | ||
| } | ||
| const F = /* @__PURE__ */ new Map(); | ||
| const ne = /* @__PURE__ */ new Map(); | ||
| typeof window < "u" && (window.registerEditorCommand = (e, t) => { | ||
| F.set(e, t); | ||
| ne.set(e, t); | ||
| }, window.executeEditorCommand = (e, t) => { | ||
| const m = F.get(e); | ||
| return m ? m(t) : (console.warn(`No handler registered for command: ${e}`), !1); | ||
| const u = ne.get(e); | ||
| return u ? u(t) : (console.warn(`No handler registered for command: ${e}`), !1); | ||
| }); | ||
| const ye = (e) => { | ||
| const t = j(() => pe(e), [ | ||
| const Ge = (e) => { | ||
| const t = ee(() => Ke(e), [ | ||
| e.id, | ||
@@ -906,2 +1212,4 @@ e.className, | ||
| e.defaultValue, | ||
| e.readonly, | ||
| e.placeholder, | ||
| e.plugins, | ||
@@ -923,40 +1231,49 @@ e.toolbar, | ||
| e.mediaConfig | ||
| ]), m = E(null), s = E(null), i = E(e.onInit), r = E(e.onDestroy), g = E(null), d = E(null), h = E(null); | ||
| A(() => { | ||
| i.current = e.onInit, r.current = e.onDestroy; | ||
| ]), u = T(null), i = T(null), r = T(e.onInit), o = T(e.onDestroy), b = T(e.onChange), h = T(/* @__PURE__ */ new Set()), c = T(null), m = T(null), s = T(null); | ||
| z(() => { | ||
| r.current = e.onInit, o.current = e.onDestroy, b.current = e.onChange; | ||
| }); | ||
| const o = j(() => { | ||
| const c = new te(); | ||
| t.plugins.forEach((b) => { | ||
| c.register(b), b.commands && typeof window < "u" && Object.entries(b.commands).forEach(([p, y]) => { | ||
| F.set(p, y); | ||
| const x = (p) => { | ||
| b.current?.(p), h.current.forEach((w) => { | ||
| try { | ||
| w(p); | ||
| } catch (a) { | ||
| console.error("Editora onChange subscriber failed:", a); | ||
| } | ||
| }); | ||
| }, L = ee(() => { | ||
| const p = new Le(); | ||
| t.plugins.forEach((a) => { | ||
| p.register(a), a.commands && typeof window < "u" && Object.entries(a.commands).forEach(([A, M]) => { | ||
| ne.set(A, M); | ||
| }); | ||
| }); | ||
| const f = new ne(c); | ||
| return m.current = f, f; | ||
| const w = new Ae(p); | ||
| return u.current = w, w; | ||
| }, [t.plugins]); | ||
| A(() => { | ||
| const c = { | ||
| getHTML: () => g.current?.querySelector(".rte-content")?.innerHTML || "", | ||
| setHTML: (f) => { | ||
| const b = g.current?.querySelector(".rte-content"); | ||
| b && (b.innerHTML = f); | ||
| z(() => { | ||
| const p = { | ||
| getHTML: () => c.current?.querySelector(".rte-content")?.innerHTML || "", | ||
| setHTML: (w) => { | ||
| const a = c.current?.querySelector(".rte-content"); | ||
| a && (a.innerHTML = w); | ||
| }, | ||
| execCommand: (f, b) => { | ||
| typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(f, b); | ||
| execCommand: (w, a) => { | ||
| typeof window < "u" && window.executeEditorCommand && (window.__editoraCommandEditorRoot = c.current || null, window.executeEditorCommand(w, a)); | ||
| }, | ||
| registerCommand: (f, b) => { | ||
| typeof window < "u" && window.registerEditorCommand && window.registerEditorCommand(f, b); | ||
| registerCommand: (w, a) => { | ||
| typeof window < "u" && window.registerEditorCommand && window.registerEditorCommand(w, a); | ||
| }, | ||
| focus: () => { | ||
| g.current?.querySelector(".rte-content")?.focus(); | ||
| c.current?.querySelector(".rte-content")?.focus(); | ||
| }, | ||
| blur: () => { | ||
| g.current?.querySelector(".rte-content")?.blur(); | ||
| c.current?.querySelector(".rte-content")?.blur(); | ||
| }, | ||
| destroy: () => { | ||
| r.current && r.current(); | ||
| o.current && o.current(); | ||
| }, | ||
| onChange: (f) => () => { | ||
| }, | ||
| onChange: (w) => (h.current.add(w), () => { | ||
| h.current.delete(w); | ||
| }), | ||
| getState: () => ({ | ||
@@ -967,49 +1284,63 @@ plugins: t.plugins, | ||
| toolbar: { | ||
| items: o.toolbar?.items || [] | ||
| items: L.toolbar?.items || [] | ||
| } | ||
| }; | ||
| return s.current = c, i.current && i.current(c), () => { | ||
| r.current && r.current(); | ||
| return i.current = p, r.current && r.current(p), () => { | ||
| h.current.clear(), o.current && o.current(); | ||
| }; | ||
| }, []), A(() => { | ||
| if (t.statusbar.enabled && h.current && g.current) { | ||
| d.current || (d.current = new oe({ | ||
| }, []), z(() => { | ||
| if (t.statusbar.enabled && s.current && c.current) { | ||
| m.current || (m.current = new xe({ | ||
| enabled: !0, | ||
| position: t.statusbar.position | ||
| }), d.current.create(h.current)); | ||
| const c = g.current.querySelector(".rte-content"); | ||
| if (c) { | ||
| const f = () => { | ||
| const b = c.textContent || "", { words: p, chars: y } = re(b), w = ae(c), S = window.getSelection(); | ||
| let x, T; | ||
| if (S && S.rangeCount > 0) { | ||
| const L = S.getRangeAt(0); | ||
| x = le(c, L), L.collapsed || (T = ie(L, x), x = void 0); | ||
| } | ||
| d.current?.update({ | ||
| wordCount: p, | ||
| charCount: y, | ||
| lineCount: w, | ||
| cursorPosition: x, | ||
| selectionInfo: T | ||
| }), m.current.create(s.current)); | ||
| const p = c.current.querySelector(".rte-content"); | ||
| if (p) { | ||
| const w = () => { | ||
| const f = document.activeElement; | ||
| return !!f && (f === p || p.contains(f)); | ||
| }, a = () => { | ||
| const f = p.getBoundingClientRect(); | ||
| return f.bottom >= 0 && f.top <= window.innerHeight; | ||
| }, A = () => { | ||
| const f = window.getSelection(); | ||
| if (!f || f.rangeCount === 0) return null; | ||
| const y = f.getRangeAt(0), F = y.commonAncestorContainer; | ||
| return p.contains(F) ? y : null; | ||
| }, M = (f = !1) => { | ||
| if (t.performance.viewportOnlyScan !== !1 && !a() && !w()) | ||
| return; | ||
| const F = A(), W = !!F || w(); | ||
| if (f && !W) | ||
| return; | ||
| const P = p.textContent || "", { words: H, chars: O } = Te(P), $ = Me(p); | ||
| let _, V; | ||
| F && (_ = Re(p, F), F.collapsed || (V = Ie(F, _), _ = void 0)), m.current?.update({ | ||
| wordCount: H, | ||
| charCount: O, | ||
| lineCount: $, | ||
| cursorPosition: _, | ||
| selectionInfo: V | ||
| }); | ||
| }, v = () => M(), k = () => M(!0), C = () => M(), R = () => M(); | ||
| return p.addEventListener("input", v), p.addEventListener("focus", C), p.addEventListener("blur", R), document.addEventListener("selectionchange", k), M(), () => { | ||
| p.removeEventListener("input", v), p.removeEventListener("focus", C), p.removeEventListener("blur", R), document.removeEventListener("selectionchange", k); | ||
| }; | ||
| return c.addEventListener("input", f), c.addEventListener("selectionchange", f), document.addEventListener("selectionchange", f), f(), () => { | ||
| c.removeEventListener("input", f), c.removeEventListener("selectionchange", f), document.removeEventListener("selectionchange", f); | ||
| }; | ||
| } | ||
| } else | ||
| d.current && (d.current.destroy(), d.current = null); | ||
| m.current && (m.current.destroy(), m.current = null); | ||
| return () => { | ||
| d.current && (d.current.destroy(), d.current = null); | ||
| m.current && (m.current.destroy(), m.current = null); | ||
| }; | ||
| }, [t.statusbar.enabled, t.statusbar.position]); | ||
| const u = t.toolbar.floating ?? !1, v = t.toolbar.position || "top", C = t.toolbar.sticky ?? !1; | ||
| return /* @__PURE__ */ l(we, { plugins: t.plugins, children: /* @__PURE__ */ R( | ||
| }, [t.statusbar.enabled, t.statusbar.position, t.performance.viewportOnlyScan]); | ||
| const N = t.toolbar.floating ?? !1, l = t.toolbar.position || "top", B = t.toolbar.sticky ?? !1, D = t.toolbar.showMoreOptions ?? !0; | ||
| return /* @__PURE__ */ d(qe, { plugins: t.plugins, children: /* @__PURE__ */ U( | ||
| "div", | ||
| { | ||
| ref: g, | ||
| ref: c, | ||
| id: t.id, | ||
| "data-editora-editor": !0, | ||
| "data-readonly": t.readonly ? "true" : "false", | ||
| className: `rte-editor ${t.className || ""}`, | ||
| lang: t.language.locale, | ||
| dir: t.language.direction, | ||
@@ -1022,18 +1353,23 @@ style: { | ||
| children: [ | ||
| v !== "bottom" && /* @__PURE__ */ l( | ||
| V, | ||
| l !== "bottom" && /* @__PURE__ */ d( | ||
| de, | ||
| { | ||
| editor: o, | ||
| position: v, | ||
| sticky: C, | ||
| floating: u | ||
| editor: L, | ||
| position: l, | ||
| sticky: B, | ||
| floating: N, | ||
| readonly: t.readonly, | ||
| showMoreOptions: D, | ||
| itemsOverride: t.toolbar.items | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| be, | ||
| /* @__PURE__ */ d( | ||
| Ue, | ||
| { | ||
| editor: o, | ||
| editor: L, | ||
| defaultValue: t.defaultValue, | ||
| value: t.value, | ||
| onChange: t.onChange, | ||
| readonly: t.readonly, | ||
| placeholder: t.placeholder, | ||
| onChange: x, | ||
| pasteConfig: t.paste, | ||
@@ -1043,25 +1379,33 @@ contentConfig: t.content, | ||
| performanceConfig: t.performance, | ||
| autosaveConfig: t.autosave | ||
| accessibilityConfig: t.accessibility, | ||
| autosaveConfig: t.autosave, | ||
| contextMenuConfig: t.contextMenu, | ||
| spellcheckConfig: t.spellcheck | ||
| } | ||
| ), | ||
| v === "bottom" && /* @__PURE__ */ l( | ||
| V, | ||
| l === "bottom" && /* @__PURE__ */ d( | ||
| de, | ||
| { | ||
| editor: o, | ||
| position: v, | ||
| sticky: C, | ||
| floating: u | ||
| editor: L, | ||
| position: l, | ||
| sticky: B, | ||
| floating: N, | ||
| readonly: t.readonly, | ||
| showMoreOptions: D, | ||
| itemsOverride: t.toolbar.items | ||
| } | ||
| ), | ||
| /* @__PURE__ */ l( | ||
| he, | ||
| /* @__PURE__ */ d( | ||
| _e, | ||
| { | ||
| editor: o, | ||
| isEnabled: u | ||
| editor: L, | ||
| isEnabled: N, | ||
| viewportOnlyScan: t.performance.viewportOnlyScan, | ||
| readonly: t.readonly | ||
| } | ||
| ), | ||
| t.statusbar.enabled && /* @__PURE__ */ l( | ||
| t.statusbar.enabled && /* @__PURE__ */ d( | ||
| "div", | ||
| { | ||
| ref: h, | ||
| ref: s, | ||
| className: "editora-statusbar-container", | ||
@@ -1074,20 +1418,20 @@ style: { order: t.statusbar.position === "top" ? -1 : 1 } | ||
| ) }); | ||
| }, Se = (e) => /* @__PURE__ */ l(ye, { ...e }); | ||
| function Te(e = {}) { | ||
| const t = E(null), m = E(e.onCommand); | ||
| return A(() => { | ||
| m.current = e.onCommand; | ||
| }), A(() => { | ||
| }, Ze = (e) => /* @__PURE__ */ d(Ge, { ...e }); | ||
| function et(e = {}) { | ||
| const t = T(null), u = T(e.onCommand); | ||
| return z(() => { | ||
| u.current = e.onCommand; | ||
| }), z(() => { | ||
| if (typeof window > "u" || e.enabled === !1) return; | ||
| const s = new _(e); | ||
| t.current = s; | ||
| const i = (g) => s.handleKeyDown(g, (h, o) => { | ||
| m.current && m.current(h, o), typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(h, o); | ||
| }), r = e.editorElement || document; | ||
| return r && r.addEventListener("keydown", i), () => { | ||
| r && r.removeEventListener("keydown", i); | ||
| const i = new ge(e); | ||
| t.current = i; | ||
| const r = (b) => i.handleKeyDown(b, (c, m) => { | ||
| u.current && u.current(c, m), typeof window < "u" && window.executeEditorCommand && window.executeEditorCommand(c, m); | ||
| }), o = e.editorElement || document; | ||
| return o && o.addEventListener("keydown", r), () => { | ||
| o && o.removeEventListener("keydown", r); | ||
| }; | ||
| }, [e.editorElement, e.enabled, e.shortcuts, e.customShortcuts]), { | ||
| getShortcuts: () => t.current?.getAllShortcuts() || [], | ||
| getShortcutForCommand: (s) => t.current?.getShortcutForCommand(s), | ||
| getShortcutForCommand: (i) => t.current?.getShortcutForCommand(i), | ||
| getShortcutsHelp: () => t.current?.getShortcutsHelp() || "", | ||
@@ -1100,9 +1444,9 @@ enable: () => t.current?.enable(), | ||
| export { | ||
| be as EditorContent, | ||
| Se as EditoraEditor, | ||
| ce as InlineMenu, | ||
| Se as RichTextEditor, | ||
| V as Toolbar, | ||
| pe as mergeConfig, | ||
| Te as useKeyboardShortcuts | ||
| Ue as EditorContent, | ||
| Ze as EditoraEditor, | ||
| Ne as InlineMenu, | ||
| Ze as RichTextEditor, | ||
| de as Toolbar, | ||
| Ke as mergeConfig, | ||
| et as useKeyboardShortcuts | ||
| }; |
+19
-7
| { | ||
| "name": "@editora/react", | ||
| "version": "1.0.3", | ||
| "version": "1.0.4", | ||
| "description": "React components for Editora - Best Free Premium Rich Text Editor. Free React WYSIWYG editor with enterprise features, 30+ free plugins, and accessibility support.", | ||
@@ -38,6 +38,6 @@ "author": "Ajay Kumar <ajaykr089@gmail.com>", | ||
| "module": "dist/index.esm.js", | ||
| "types": "dist/index.d.ts", | ||
| "types": "index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "types": "./index.d.ts", | ||
| "import": "./dist/index.esm.js", | ||
@@ -49,2 +49,4 @@ "require": "./dist/index.cjs.js" | ||
| "dist", | ||
| "index.d.ts", | ||
| "!dist/**/*.map", | ||
| "README.md", | ||
@@ -60,11 +62,21 @@ "LICENSE" | ||
| "peerDependencies": { | ||
| "@editora/core": "^1.0.0", | ||
| "react": ">=16.8.0", | ||
| "react-dom": ">=16.8.0" | ||
| "@editora/core": "^1.0.4", | ||
| "@editora/plugins": "^1.0.4", | ||
| "@editora/themes": "^1.0.4", | ||
| "react": ">=16.8.0 <20", | ||
| "react-dom": ">=16.8.0 <20" | ||
| }, | ||
| "peerDependenciesMeta": { | ||
| "@editora/plugins": { | ||
| "optional": true | ||
| }, | ||
| "@editora/themes": { | ||
| "optional": true | ||
| } | ||
| }, | ||
| "dependencies": { | ||
| "@editora/core": "^1.0.3", | ||
| "@editora/light-code-editor": "^1.0.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@editora/core": "^1.0.4", | ||
| "@types/react": "^18.2.0", | ||
@@ -71,0 +83,0 @@ "@types/react-dom": "^18.2.0", |
+55
-13
@@ -20,2 +20,20 @@ # @editora/react | ||
| ### Runtime Dependency Matrix | ||
| - Required: `@editora/react`, `@editora/core`, `react`, `react-dom` | ||
| - Optional but recommended: `@editora/plugins` (toolbar/plugin features), `@editora/themes` (default/dark/acme CSS) | ||
| - For smaller bundles: prefer `@editora/plugins/lite` or per-plugin subpaths like `@editora/plugins/bold`, and lazy-load heavy plugins (`document-manager`, `media-manager`, `spell-check`) via dynamic imports. | ||
| Minimal install: | ||
| ```bash | ||
| npm install @editora/react @editora/core react react-dom | ||
| ``` | ||
| Full-featured install: | ||
| ```bash | ||
| npm install @editora/react @editora/core @editora/plugins @editora/themes react react-dom | ||
| ``` | ||
| ## 🎯 Overview | ||
@@ -107,2 +125,19 @@ | ||
| ### Performance + Accessibility Config | ||
| ```tsx | ||
| <EditoraEditor | ||
| plugins={[BoldPlugin(), ItalicPlugin()]} | ||
| accessibility={{ | ||
| enableARIA: true, | ||
| keyboardNavigation: true, | ||
| checker: true, // auto-enables a11y checker if factory/plugin is available | ||
| }} | ||
| performance={{ | ||
| debounceInputMs: 120, | ||
| viewportOnlyScan: true, | ||
| }} | ||
| /> | ||
| ``` | ||
| ### With Custom Toolbar | ||
@@ -169,3 +204,2 @@ | ||
| style?: React.CSSProperties; | ||
| theme?: 'light' | 'dark' | 'auto'; | ||
@@ -272,4 +306,8 @@ // Toolbar | ||
| import "@editora/themes/themes/default.css"; | ||
| import "@editora/themes/themes/dark.css"; | ||
| import "@editora/themes/themes/acme.css"; | ||
| <EditoraEditor theme="dark" /> | ||
| <div data-theme="dark"> | ||
| <EditoraEditor /> | ||
| </div> | ||
| ``` | ||
@@ -280,19 +318,23 @@ | ||
| ```css | ||
| :root { | ||
| --editora-bg: #ffffff; | ||
| --editora-text: #000000; | ||
| --editora-border: #cccccc; | ||
| --editora-primary: #0066cc; | ||
| --editora-toolbar-bg: #f5f5f5; | ||
| :is([data-theme="custom-brand"], .editora-theme-custom-brand) { | ||
| --rte-color-primary: #2563eb; | ||
| --rte-color-primary-hover: #1d4ed8; | ||
| --rte-color-text-primary: #0f172a; | ||
| --rte-color-bg-primary: #ffffff; | ||
| --rte-color-border: #cbd5e1; | ||
| } | ||
| [data-theme="dark"] { | ||
| --editora-bg: #1e1e1e; | ||
| --editora-text: #ffffff; | ||
| --editora-border: #444444; | ||
| --editora-primary: #3399ff; | ||
| --editora-toolbar-bg: #2d2d2d; | ||
| --rte-color-primary: #58a6ff; | ||
| } | ||
| ``` | ||
| Apply it in React with a wrapper: | ||
| ```tsx | ||
| <div data-theme="custom-brand"> | ||
| <EditoraEditor /> | ||
| </div> | ||
| ``` | ||
| ## 🔌 Plugin Configuration | ||
@@ -299,0 +341,0 @@ |
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
98187
39.73%5
25%1732
46.66%534
8.54%6
20%5
25%3
50%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed