@editora/core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +9 -0
  2. package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs +475 -0
  3. package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs.map +1 -0
  4. package/dist/AnchorPlugin.native-7es9PVZ9.mjs +340 -0
  5. package/dist/AnchorPlugin.native-7es9PVZ9.mjs.map +1 -0
  6. package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs +449 -0
  7. package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs.map +1 -0
  8. package/dist/BlockquotePlugin.native-JFmOLsxN.mjs +48 -0
  9. package/dist/BlockquotePlugin.native-JFmOLsxN.mjs.map +1 -0
  10. package/dist/BoldPlugin.native-BAzzoqU5.mjs +45 -0
  11. package/dist/BoldPlugin.native-BAzzoqU5.mjs.map +1 -0
  12. package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs +79 -0
  13. package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs.map +1 -0
  14. package/dist/ChecklistPlugin.native-Dccs3nLe.mjs +153 -0
  15. package/dist/ChecklistPlugin.native-Dccs3nLe.mjs.map +1 -0
  16. package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs +27 -0
  17. package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs.map +1 -0
  18. package/dist/CodePlugin.native-DD9xFIid.mjs +1679 -0
  19. package/dist/CodePlugin.native-DD9xFIid.mjs.map +1 -0
  20. package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs +326 -0
  21. package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs.map +1 -0
  22. package/dist/CommentsPlugin.native-2zQV8Ia4.mjs +473 -0
  23. package/dist/CommentsPlugin.native-2zQV8Ia4.mjs.map +1 -0
  24. package/dist/DirectionPlugin.native-Be7wCzkI.mjs +59 -0
  25. package/dist/DirectionPlugin.native-Be7wCzkI.mjs.map +1 -0
  26. package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs +116 -0
  27. package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs.map +1 -0
  28. package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs +461 -0
  29. package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs.map +1 -0
  30. package/dist/EmojisPlugin.native-D6mJSnSR.mjs +1033 -0
  31. package/dist/EmojisPlugin.native-D6mJSnSR.mjs.map +1 -0
  32. package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs +106 -0
  33. package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs.map +1 -0
  34. package/dist/FontSizePlugin.native-DkLMLPue.mjs +186 -0
  35. package/dist/FontSizePlugin.native-DkLMLPue.mjs.map +1 -0
  36. package/dist/FootnotePlugin.native-BciVc9W6.mjs +128 -0
  37. package/dist/FootnotePlugin.native-BciVc9W6.mjs.map +1 -0
  38. package/dist/FullscreenPlugin.native-ChXyxeNw.mjs +77 -0
  39. package/dist/FullscreenPlugin.native-ChXyxeNw.mjs.map +1 -0
  40. package/dist/HeadingPlugin.native-DrLYwQnQ.mjs +64 -0
  41. package/dist/HeadingPlugin.native-DrLYwQnQ.mjs.map +1 -0
  42. package/dist/HistoryPlugin.native-DoDRifCf.mjs +89 -0
  43. package/dist/HistoryPlugin.native-DoDRifCf.mjs.map +1 -0
  44. package/dist/IndentPlugin.native-CbFugPoi.mjs +133 -0
  45. package/dist/IndentPlugin.native-CbFugPoi.mjs.map +1 -0
  46. package/dist/ItalicPlugin.native-CQjjDyUL.mjs +43 -0
  47. package/dist/ItalicPlugin.native-CQjjDyUL.mjs.map +1 -0
  48. package/dist/LineHeightPlugin.native-CWQT2FIa.mjs +73 -0
  49. package/dist/LineHeightPlugin.native-CWQT2FIa.mjs.map +1 -0
  50. package/dist/LinkPlugin.native-BdAOV-iu.mjs +206 -0
  51. package/dist/LinkPlugin.native-BdAOV-iu.mjs.map +1 -0
  52. package/dist/ListPlugin.native-CLFU5AUQ.mjs +59 -0
  53. package/dist/ListPlugin.native-CLFU5AUQ.mjs.map +1 -0
  54. package/dist/MathPlugin.native-DE_ii-LA.mjs +182 -0
  55. package/dist/MathPlugin.native-DE_ii-LA.mjs.map +1 -0
  56. package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs +533 -0
  57. package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs.map +1 -0
  58. package/dist/MergeTagPlugin.native-CrxyThyn.mjs +178 -0
  59. package/dist/MergeTagPlugin.native-CrxyThyn.mjs.map +1 -0
  60. package/dist/PageBreakPlugin.native-DDjcDyRW.mjs +172 -0
  61. package/dist/PageBreakPlugin.native-DDjcDyRW.mjs.map +1 -0
  62. package/dist/PreviewPlugin.native-DBvfpmIv.mjs +322 -0
  63. package/dist/PreviewPlugin.native-DBvfpmIv.mjs.map +1 -0
  64. package/dist/PrintPlugin.native-BUpm52VJ.mjs +311 -0
  65. package/dist/PrintPlugin.native-BUpm52VJ.mjs.map +1 -0
  66. package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs +731 -0
  67. package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs.map +1 -0
  68. package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs +465 -0
  69. package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs.map +1 -0
  70. package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs +43 -0
  71. package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs.map +1 -0
  72. package/dist/TablePlugin.native-EEWXn1-s.mjs +491 -0
  73. package/dist/TablePlugin.native-EEWXn1-s.mjs.map +1 -0
  74. package/dist/TemplatePlugin.native-BlSn1c9h.mjs +564 -0
  75. package/dist/TemplatePlugin.native-BlSn1c9h.mjs.map +1 -0
  76. package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs +97 -0
  77. package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs.map +1 -0
  78. package/dist/TextColorPlugin.native-D6SmTglm.mjs +432 -0
  79. package/dist/TextColorPlugin.native-D6SmTglm.mjs.map +1 -0
  80. package/dist/UnderlinePlugin.native-QpIcK4L2.mjs +35 -0
  81. package/dist/UnderlinePlugin.native-QpIcK4L2.mjs.map +1 -0
  82. package/dist/core.css +1 -0
  83. package/dist/documentManager-irzj9n3V.mjs +37627 -0
  84. package/dist/documentManager-irzj9n3V.mjs.map +1 -0
  85. package/dist/editorContainerHelpers-C7kdWnS0.mjs +27 -0
  86. package/dist/editorContainerHelpers-C7kdWnS0.mjs.map +1 -0
  87. package/dist/editora.min.js +519 -4
  88. package/dist/editora.min.js.map +1 -0
  89. package/dist/editora.umd.js +519 -4
  90. package/dist/editora.umd.js.map +1 -0
  91. package/dist/index-BF5RBhL9.js +4 -0
  92. package/dist/index-BF5RBhL9.js.map +1 -0
  93. package/dist/index-BPsf460l.mjs +1243 -0
  94. package/dist/index-BPsf460l.mjs.map +1 -0
  95. package/dist/index.cjs.js +517 -4
  96. package/dist/index.cjs.js.map +1 -0
  97. package/dist/index.es-CuicffkQ.mjs +6665 -0
  98. package/dist/index.es-CuicffkQ.mjs.map +1 -0
  99. package/dist/index.esm.js +1403 -122
  100. package/dist/index.esm.js.map +1 -0
  101. package/dist/plugin-loader.js +55 -0
  102. package/dist/plugin-loader.js.map +1 -0
  103. package/dist/purify.es-CKpwg8Tk.mjs +471 -0
  104. package/dist/purify.es-CKpwg8Tk.mjs.map +1 -0
  105. package/dist/webcomponent-core.js +1243 -0
  106. package/dist/webcomponent-core.js.map +1 -0
  107. package/dist/webcomponent-core.min.css +1 -0
  108. package/dist/webcomponent-core.min.js +597 -0
  109. package/dist/webcomponent-core.min.js.map +1 -0
  110. package/dist/webcomponent.cjs.js +2 -0
  111. package/dist/webcomponent.cjs.js.map +1 -0
  112. package/dist/webcomponent.esm.js +6 -0
  113. package/dist/webcomponent.esm.js.map +1 -0
  114. package/dist/webcomponent.js +1286 -0
  115. package/dist/webcomponent.js.map +1 -0
  116. package/dist/webcomponent.min.css +1 -0
  117. package/dist/webcomponent.min.js +4076 -0
  118. package/dist/webcomponent.min.js.map +1 -0
  119. package/package.json +64 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaManagerPlugin.native-DaYFDzNM.mjs","sources":["../../plugins/media-manager/src/MediaManagerPlugin.native.ts"],"sourcesContent":["import { Plugin } from '@editora/core';\n\n/**\n * Media Manager Plugin - Native Implementation\n * \n * Features:\n * - Insert images and videos with full dialog UI\n * - Drag & drop file upload\n * - URL input with dimensions\n * - Inline resize handles (drag corners to resize)\n * - Floating toolbar on image selection\n * - Link images\n */\n\nlet savedSelection: Range | null = null;\nlet selectedMedia: HTMLImageElement | HTMLVideoElement | null = null;\nlet floatingToolbar: HTMLDivElement | null = null;\nlet resizeHandles: HTMLDivElement[] = [];\nlet isResizing = false;\nlet currentHandle: string | null = null;\nlet startX = 0;\nlet startY = 0;\nlet startWidth = 0;\nlet startHeight = 0;\nlet aspectRatio = 1;\nlet editorElement: HTMLElement | null = null; // Editor instance context\n\ndeclare global {\n interface Window {\n __mediaManagerInitialized?: boolean;\n }\n}\n\nconst showMediaDialog = (type: 'image' | 'video') => {\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n savedSelection = selection.getRangeAt(0).cloneRange();\n }\n\n const overlay = document.createElement('div');\n overlay.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 99999;';\n\n const dialog = document.createElement('div');\n dialog.style.cssText = 'background: white; border-radius: 8px; width: 90%; max-width: 600px; max-height: 90vh; overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);';\n\n let activeTab: 'upload' | 'url' = 'upload';\n let urlValue = '';\n let widthValue = '';\n let heightValue = '';\n let altValue = '';\n\n const renderDialog = () => {\n dialog.innerHTML = `\n <div style=\"display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid #e1e5e9; background: #f8f9fa;\">\n <h2 style=\"margin: 0; font-size: 18px; font-weight: 600;\">Insert ${type === 'image' ? 'Image' : 'Video'}</h2>\n <button class=\"close-btn\" style=\"background: none; border: none; font-size: 28px; cursor: pointer; color: #6c757d; padding: 0; width: 30px; height: 30px; line-height: 1;\">×</button>\n </div>\n\n <div class=\"tabs\" style=\"display: flex; border-bottom: 1px solid #e1e5e9;\">\n <button class=\"tab-upload\" style=\"flex: 1; padding: 12px; border: none; background: ${activeTab === 'upload' ? '#007bff' : '#f8f9fa'}; color: ${activeTab === 'upload' ? 'white' : '#495057'}; cursor: pointer; font-weight: 500;\">📤 Upload</button>\n <button class=\"tab-url\" style=\"flex: 1; padding: 12px; border: none; background: ${activeTab === 'url' ? '#007bff' : '#f8f9fa'}; color: ${activeTab === 'url' ? 'white' : '#495057'}; cursor: pointer; font-weight: 500;\">🔗 URL</button>\n </div>\n\n <div style=\"padding: 20px; overflow-y: auto; flex: 1;\">\n ${activeTab === 'upload' ? `\n <div id=\"upload-section\">\n <div class=\"dropzone\" style=\"border: 2px dashed #ced4da; border-radius: 8px; padding: 40px; text-align: center; cursor: pointer; transition: all 0.3s;\">\n <div style=\"font-size: 48px; margin-bottom: 10px;\">📁</div>\n <p style=\"margin: 0 0 8px 0; font-weight: 600; font-size: 16px;\">Drag and drop your ${type} here</p>\n <p style=\"margin: 0 0 8px 0; color: #6c757d; font-size: 14px;\">or click to browse</p>\n <p style=\"margin: 0; color: #6c757d; font-size: 12px;\">Max file size: 50MB</p>\n </div>\n <input type=\"file\" id=\"file-input\" accept=\"${type === 'image' ? 'image/*' : 'video/*'}\" style=\"display: none;\">\n <div id=\"upload-progress\" style=\"display: none; margin-top: 20px;\">\n <div style=\"background: #e9ecef; border-radius: 4px; height: 8px; overflow: hidden;\">\n <div id=\"progress-bar\" style=\"background: #007bff; height: 100%; width: 0%; transition: width 0.3s;\"></div>\n </div>\n <p id=\"progress-text\" style=\"margin-top: 8px; text-align: center; color: #6c757d; font-size: 14px;\">Uploading...</p>\n </div>\n </div>\n ` : `\n <div id=\"url-section\">\n <div style=\"margin-bottom: 20px;\">\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">URL:</label>\n <input type=\"text\" id=\"url-input\" placeholder=\"https://example.com/${type}.${type === 'image' ? 'jpg' : 'mp4'}\" value=\"${urlValue}\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\">\n </div>\n ${type === 'image' ? `\n <div style=\"margin-bottom: 20px;\">\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">Alt Text (for accessibility):</label>\n <input type=\"text\" id=\"alt-input\" placeholder=\"Describe the image\" value=\"${altValue}\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\">\n </div>\n ` : ''}\n <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 20px;\">\n <div>\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">Width (px):</label>\n <input type=\"number\" id=\"width-input\" placeholder=\"Auto\" value=\"${widthValue}\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\">\n </div>\n <div>\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">Height (px):</label>\n <input type=\"number\" id=\"height-input\" placeholder=\"Auto\" value=\"${heightValue}\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\">\n </div>\n </div>\n ${urlValue ? `\n <div style=\"margin-bottom: 20px;\">\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">Preview:</label>\n <div style=\"border: 1px solid #dee2e6; border-radius: 4px; padding: 10px; background: #f8f9fa; text-align: center;\">\n ${type === 'image' ? `<img src=\"${urlValue}\" alt=\"Preview\" style=\"max-width: 100%; max-height: 200px;\">` : `<video src=\"${urlValue}\" controls style=\"max-width: 100%; max-height: 200px;\"></video>`}\n </div>\n </div>\n ` : ''}\n </div>\n `}\n </div>\n\n <div style=\"display: flex; justify-content: flex-end; gap: 10px; padding: 16px 20px; border-top: 1px solid #e1e5e9; background: #f8f9fa;\">\n <button class=\"cancel-btn\" style=\"padding: 10px 20px; background: #fff; border: 1px solid #ced4da; border-radius: 4px; cursor: pointer; font-size: 14px;\">Cancel</button>\n <button id=\"insert-btn\" style=\"padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;\" ${!urlValue && activeTab === 'url' ? 'disabled' : ''}>Insert</button>\n </div>\n `;\n };\n\n renderDialog();\n overlay.appendChild(dialog);\n document.body.appendChild(overlay);\n\n const closeDialog = () => document.body.removeChild(overlay);\n\n const insertMedia = () => {\n if (!urlValue) return;\n\n const mediaEl = type === 'image' ? document.createElement('img') : document.createElement('video');\n mediaEl.src = urlValue;\n mediaEl.setAttribute('data-media-type', type);\n \n if (type === 'image' && altValue) {\n (mediaEl as HTMLImageElement).alt = altValue;\n }\n if (widthValue) {\n mediaEl.style.width = `${widthValue}px`;\n mediaEl.setAttribute('width', widthValue);\n }\n if (heightValue) {\n mediaEl.style.height = `${heightValue}px`;\n mediaEl.setAttribute('height', heightValue);\n }\n \n if (type === 'video') {\n (mediaEl as HTMLVideoElement).controls = true;\n }\n\n if (!widthValue && !heightValue) {\n mediaEl.style.cssText = 'max-width: 100%; height: auto; display: block; margin: 1em 0; cursor: pointer;';\n } else {\n mediaEl.style.cssText = `display: block; margin: 1em 0; cursor: pointer; ${widthValue ? `width: ${widthValue}px;` : 'max-width: 100%;'} ${heightValue ? `height: ${heightValue}px;` : 'height: auto;'}`;\n }\n \n if (savedSelection) {\n savedSelection.deleteContents();\n savedSelection.insertNode(mediaEl);\n }\n\n closeDialog();\n };\n\n const handleFileUpload = async (file: File) => {\n const progressDiv = dialog.querySelector('#upload-progress') as HTMLDivElement;\n const progressBar = dialog.querySelector('#progress-bar') as HTMLDivElement;\n const progressText = dialog.querySelector('#progress-text') as HTMLParagraphElement;\n\n if (progressDiv && progressBar && progressText) {\n progressDiv.style.display = 'block';\n\n let progress = 0;\n const interval = setInterval(() => {\n progress += Math.random() * 30;\n if (progress > 90) progress = 90;\n progressBar.style.width = `${progress}%`;\n }, 200);\n\n try {\n const reader = new FileReader();\n reader.onload = () => {\n clearInterval(interval);\n progressBar.style.width = '100%';\n progressText.textContent = '✅ Upload complete';\n \n setTimeout(() => {\n urlValue = reader.result as string;\n activeTab = 'url';\n renderDialog();\n attachEventHandlers();\n }, 500);\n };\n reader.readAsDataURL(file);\n } catch (error) {\n clearInterval(interval);\n progressText.textContent = '❌ Upload failed';\n }\n }\n };\n\n const attachEventHandlers = () => {\n const closeBtn = dialog.querySelector('.close-btn') as HTMLButtonElement;\n const cancelBtn = dialog.querySelector('.cancel-btn') as HTMLButtonElement;\n const insertBtn = dialog.querySelector('#insert-btn') as HTMLButtonElement;\n const tabUpload = dialog.querySelector('.tab-upload') as HTMLButtonElement;\n const tabUrl = dialog.querySelector('.tab-url') as HTMLButtonElement;\n\n closeBtn?.addEventListener('click', closeDialog);\n cancelBtn?.addEventListener('click', closeDialog);\n insertBtn?.addEventListener('click', insertMedia);\n\n tabUpload?.addEventListener('click', () => {\n activeTab = 'upload';\n renderDialog();\n attachEventHandlers();\n });\n\n tabUrl?.addEventListener('click', () => {\n activeTab = 'url';\n renderDialog();\n attachEventHandlers();\n });\n\n if (activeTab === 'upload') {\n const dropzone = dialog.querySelector('.dropzone') as HTMLDivElement;\n const fileInput = dialog.querySelector('#file-input') as HTMLInputElement;\n\n dropzone?.addEventListener('click', () => fileInput?.click());\n \n dropzone?.addEventListener('dragover', (e) => {\n e.preventDefault();\n dropzone.style.borderColor = '#007bff';\n dropzone.style.background = '#f0f8ff';\n });\n\n dropzone?.addEventListener('dragleave', () => {\n dropzone.style.borderColor = '#ced4da';\n dropzone.style.background = 'transparent';\n });\n\n dropzone?.addEventListener('drop', (e) => {\n e.preventDefault();\n dropzone.style.borderColor = '#ced4da';\n dropzone.style.background = 'transparent';\n const file = e.dataTransfer?.files[0];\n if (file) handleFileUpload(file);\n });\n\n fileInput?.addEventListener('change', (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (file) handleFileUpload(file);\n });\n }\n\n if (activeTab === 'url') {\n const urlInput = dialog.querySelector('#url-input') as HTMLInputElement;\n const altInput = dialog.querySelector('#alt-input') as HTMLInputElement;\n const widthInput = dialog.querySelector('#width-input') as HTMLInputElement;\n const heightInput = dialog.querySelector('#height-input') as HTMLInputElement;\n\n urlInput?.addEventListener('input', () => {\n urlValue = urlInput.value;\n renderDialog();\n attachEventHandlers();\n });\n\n altInput?.addEventListener('input', () => {\n altValue = altInput.value;\n });\n\n widthInput?.addEventListener('input', () => {\n widthValue = widthInput.value;\n });\n\n heightInput?.addEventListener('input', () => {\n heightValue = heightInput.value;\n });\n }\n };\n\n attachEventHandlers();\n overlay.addEventListener('click', (e) => { if (e.target === overlay) closeDialog(); });\n};\n\n// Create resize handles\nconst createResizeHandles = () => {\n const positions = ['nw', 'ne', 'sw', 'se'];\n positions.forEach(pos => {\n const handle = document.createElement('div');\n handle.className = `media-resize-handle-${pos}`;\n handle.style.cssText = `\n position: fixed;\n width: 10px;\n height: 10px;\n background: #007bff;\n border: 2px solid white;\n border-radius: 50%;\n cursor: ${pos}-resize;\n z-index: 10001;\n display: none;\n box-shadow: 0 1px 3px rgba(0,0,0,0.3);\n `;\n handle.setAttribute('data-position', pos);\n document.body.appendChild(handle);\n resizeHandles.push(handle);\n });\n};\n\n// Update resize handle positions\nconst updateResizeHandles = () => {\n if (!selectedMedia) {\n resizeHandles.forEach(h => h.style.display = 'none');\n return;\n }\n\n const rect = selectedMedia.getBoundingClientRect();\n const positions = {\n nw: { x: rect.left - 5, y: rect.top - 5 },\n ne: { x: rect.right - 5, y: rect.top - 5 },\n sw: { x: rect.left - 5, y: rect.bottom - 5 },\n se: { x: rect.right - 5, y: rect.bottom - 5 }\n };\n\n resizeHandles.forEach(handle => {\n const pos = handle.getAttribute('data-position') as keyof typeof positions;\n const coord = positions[pos];\n handle.style.left = `${coord.x}px`;\n handle.style.top = `${coord.y}px`;\n handle.style.display = 'block';\n });\n};\n\n// Show Alt Text dialog\nconst showAltTextDialog = (img: HTMLImageElement) => {\n const overlay = document.createElement('div');\n overlay.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10001;';\n\n const dialog = document.createElement('div');\n dialog.style.cssText = 'background: white; border-radius: 8px; width: 90%; max-width: 500px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);';\n\n dialog.innerHTML = `\n <div style=\"display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid #e1e5e9; background: #f8f9fa;\">\n <h2 style=\"margin: 0; font-size: 18px; font-weight: 600;\">Edit Alt Text</h2>\n <button class=\"close-btn\" style=\"background: none; border: none; font-size: 28px; cursor: pointer; color: #6c757d; padding: 0; width: 30px; height: 30px; line-height: 1;\">×</button>\n </div>\n <div style=\"padding: 20px;\">\n <label style=\"display: block; margin-bottom: 8px; font-weight: 500;\">Alternative Text (for accessibility):</label>\n <textarea id=\"alt-text-input\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px; min-height: 80px; font-family: inherit; resize: vertical;\" placeholder=\"Describe the image for screen readers...\">${img.alt || ''}</textarea>\n <p style=\"margin-top: 8px; margin-bottom: 0; font-size: 12px; color: #6c757d;\">Good alt text is descriptive and concise. It helps users with visual impairments understand your content.</p>\n </div>\n <div style=\"display: flex; justify-content: flex-end; gap: 10px; padding: 16px 20px; border-top: 1px solid #e1e5e9; background: #f8f9fa;\">\n <button class=\"cancel-btn\" style=\"padding: 10px 20px; background: #fff; border: 1px solid #ced4da; border-radius: 4px; cursor: pointer; font-size: 14px;\">Cancel</button>\n <button class=\"save-btn\" style=\"padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;\">Save</button>\n </div>\n `;\n\n overlay.appendChild(dialog);\n document.body.appendChild(overlay);\n\n const input = dialog.querySelector('#alt-text-input') as HTMLTextAreaElement;\n const closeBtn = dialog.querySelector('.close-btn') as HTMLButtonElement;\n const cancelBtn = dialog.querySelector('.cancel-btn') as HTMLButtonElement;\n const saveBtn = dialog.querySelector('.save-btn') as HTMLButtonElement;\n\n const closeDialog = () => document.body.removeChild(overlay);\n\n closeBtn.addEventListener('click', closeDialog);\n cancelBtn.addEventListener('click', closeDialog);\n overlay.addEventListener('click', (e) => { if (e.target === overlay) closeDialog(); });\n\n saveBtn.addEventListener('click', () => {\n img.alt = input.value;\n closeDialog();\n });\n\n input.focus();\n input.select();\n};\n\n// Show Link dialog for media\nconst showLinkDialogForMedia = (media: HTMLImageElement | HTMLVideoElement) => {\n const existingLink = (media as HTMLElement).closest('a');\n const currentHref = existingLink?.getAttribute('href') || '';\n const currentTarget = existingLink?.getAttribute('target') || '_self';\n const currentTitle = existingLink?.getAttribute('title') || '';\n\n const overlay = document.createElement('div');\n overlay.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10001;';\n\n const dialog = document.createElement('div');\n dialog.style.cssText = 'background: white; border-radius: 8px; width: 90%; max-width: 500px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);';\n\n dialog.innerHTML = `\n <div style=\"display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid #e1e5e9; background: #f8f9fa;\">\n <h2 style=\"margin: 0; font-size: 18px; font-weight: 600;\">${existingLink ? 'Edit Link' : 'Add Link'}</h2>\n <button class=\"close-btn\" style=\"background: none; border: none; font-size: 28px; cursor: pointer; color: #6c757d; padding: 0; width: 30px; height: 30px; line-height: 1;\">×</button>\n </div>\n <div style=\"padding: 20px;\">\n <div style=\"margin-bottom: 16px;\">\n <label style=\"display: block; margin-bottom: 6px; font-weight: 500;\">URL:</label>\n <input id=\"link-url\" type=\"url\" value=\"${currentHref}\" placeholder=\"https://example.com\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\" />\n </div>\n <div style=\"margin-bottom: 16px;\">\n <label style=\"display: block; margin-bottom: 6px; font-weight: 500;\">Title (tooltip):</label>\n <input id=\"link-title\" type=\"text\" value=\"${currentTitle}\" placeholder=\"Optional tooltip text\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\" />\n </div>\n <div>\n <label style=\"display: flex; align-items: center; cursor: pointer;\">\n <input id=\"link-target\" type=\"checkbox\" ${currentTarget === '_blank' ? 'checked' : ''} style=\"margin-right: 8px;\" />\n Open in new window/tab\n </label>\n </div>\n </div>\n <div style=\"display: flex; justify-content: space-between; padding: 16px 20px; border-top: 1px solid #e1e5e9; background: #f8f9fa;\">\n ${existingLink ? '<button class=\"remove-link-btn\" style=\"padding: 10px 20px; background: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;\">Remove Link</button>' : '<span></span>'}\n <div style=\"display: flex; gap: 10px;\">\n <button class=\"cancel-btn\" style=\"padding: 10px 20px; background: #fff; border: 1px solid #ced4da; border-radius: 4px; cursor: pointer; font-size: 14px;\">Cancel</button>\n <button class=\"save-btn\" style=\"padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;\">Save</button>\n </div>\n </div>\n `;\n\n overlay.appendChild(dialog);\n document.body.appendChild(overlay);\n\n const urlInput = dialog.querySelector('#link-url') as HTMLInputElement;\n const titleInput = dialog.querySelector('#link-title') as HTMLInputElement;\n const targetCheckbox = dialog.querySelector('#link-target') as HTMLInputElement;\n const closeBtn = dialog.querySelector('.close-btn') as HTMLButtonElement;\n const cancelBtn = dialog.querySelector('.cancel-btn') as HTMLButtonElement;\n const saveBtn = dialog.querySelector('.save-btn') as HTMLButtonElement;\n const removeLinkBtn = dialog.querySelector('.remove-link-btn') as HTMLButtonElement;\n\n const closeDialog = () => document.body.removeChild(overlay);\n\n closeBtn.addEventListener('click', closeDialog);\n cancelBtn.addEventListener('click', closeDialog);\n overlay.addEventListener('click', (e) => { if (e.target === overlay) closeDialog(); });\n\n saveBtn.addEventListener('click', () => {\n const url = urlInput.value.trim();\n if (url) {\n const normalized = url.startsWith('http') ? url : `https://${url}`;\n \n if (existingLink) {\n existingLink.setAttribute('href', normalized);\n existingLink.setAttribute('target', targetCheckbox.checked ? '_blank' : '_self');\n if (targetCheckbox.checked) {\n existingLink.setAttribute('rel', 'noopener noreferrer');\n } else {\n existingLink.removeAttribute('rel');\n }\n if (titleInput.value.trim()) {\n existingLink.setAttribute('title', titleInput.value.trim());\n } else {\n existingLink.removeAttribute('title');\n }\n } else {\n const link = document.createElement('a');\n link.href = normalized;\n link.target = targetCheckbox.checked ? '_blank' : '_self';\n if (targetCheckbox.checked) {\n link.rel = 'noopener noreferrer';\n }\n if (titleInput.value.trim()) {\n link.title = titleInput.value.trim();\n }\n media.replaceWith(link);\n link.appendChild(media);\n }\n \n closeDialog();\n \n // Update toolbar to reflect link state\n if (floatingToolbar && selectedMedia) {\n showFloatingToolbar(selectedMedia);\n }\n }\n });\n\n removeLinkBtn?.addEventListener('click', () => {\n if (existingLink && confirm('Remove link from this media?')) {\n existingLink.replaceWith(media);\n closeDialog();\n \n // Update toolbar\n if (floatingToolbar && selectedMedia) {\n showFloatingToolbar(selectedMedia);\n }\n }\n });\n\n urlInput.focus();\n};\n\n// Show Replace Image dialog\nconst showReplaceImageDialog = (img: HTMLImageElement) => {\n const overlay = document.createElement('div');\n overlay.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10001;';\n\n const dialog = document.createElement('div');\n dialog.style.cssText = 'background: white; border-radius: 8px; width: 90%; max-width: 600px; max-height: 90vh; overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);';\n\n let activeTab: 'upload' | 'url' = 'url';\n let urlValue = img.src;\n\n const renderDialog = () => {\n dialog.innerHTML = `\n <div style=\"display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid #e1e5e9; background: #f8f9fa;\">\n <h2 style=\"margin: 0; font-size: 18px; font-weight: 600;\">Replace Image</h2>\n <button class=\"close-btn\" style=\"background: none; border: none; font-size: 28px; cursor: pointer; color: #6c757d; padding: 0; width: 30px; height: 30px; line-height: 1;\">×</button>\n </div>\n\n <div class=\"tabs\" style=\"display: flex; border-bottom: 1px solid #e1e5e9;\">\n <button class=\"tab-upload\" style=\"flex: 1; padding: 12px; border: none; background: ${activeTab === 'upload' ? '#007bff' : '#f8f9fa'}; color: ${activeTab === 'upload' ? 'white' : '#495057'}; cursor: pointer; font-weight: 500;\">📤 Upload</button>\n <button class=\"tab-url\" style=\"flex: 1; padding: 12px; border: none; background: ${activeTab === 'url' ? '#007bff' : '#f8f9fa'}; color: ${activeTab === 'url' ? 'white' : '#495057'}; cursor: pointer; font-weight: 500;\">🔗 URL</button>\n </div>\n\n <div style=\"padding: 20px; overflow-y: auto; flex: 1;\">\n ${activeTab === 'upload' ? `\n <div id=\"upload-section\">\n <div class=\"dropzone\" style=\"border: 2px dashed #ced4da; border-radius: 8px; padding: 40px; text-align: center; cursor: pointer; transition: all 0.3s;\">\n <div style=\"font-size: 48px; margin-bottom: 10px;\">📁</div>\n <p style=\"margin: 0 0 8px 0; font-weight: 600; font-size: 16px;\">Drag and drop your image here</p>\n <p style=\"margin: 0 0 8px 0; color: #6c757d; font-size: 14px;\">or click to browse</p>\n </div>\n <input type=\"file\" id=\"file-input\" accept=\"image/*\" style=\"display: none;\">\n <div id=\"upload-progress\" style=\"display: none; margin-top: 20px;\">\n <div style=\"background: #e9ecef; border-radius: 4px; height: 8px; overflow: hidden;\">\n <div id=\"progress-bar\" style=\"background: #007bff; height: 100%; width: 0%; transition: width 0.3s;\"></div>\n </div>\n <p id=\"progress-text\" style=\"margin-top: 8px; text-align: center; color: #6c757d; font-size: 14px;\">Uploading...</p>\n </div>\n </div>\n ` : `\n <div id=\"url-section\">\n <div style=\"margin-bottom: 20px;\">\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">Image URL:</label>\n <input type=\"text\" id=\"url-input\" placeholder=\"https://example.com/image.jpg\" value=\"${urlValue}\" style=\"width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px;\">\n </div>\n ${urlValue ? `\n <div style=\"margin-bottom: 20px;\">\n <label style=\"display: block; font-weight: 600; margin-bottom: 8px; font-size: 14px;\">Preview:</label>\n <div style=\"border: 1px solid #dee2e6; border-radius: 4px; padding: 10px; background: #f8f9fa; text-align: center;\">\n <img src=\"${urlValue}\" alt=\"Preview\" style=\"max-width: 100%; max-height: 300px;\" onerror=\"this.parentElement.innerHTML='<p style=&quot;color: #dc3545;&quot;>Failed to load image</p>'\">\n </div>\n </div>\n ` : ''}\n </div>\n `}\n </div>\n\n <div style=\"display: flex; justify-content: flex-end; gap: 10px; padding: 16px 20px; border-top: 1px solid #e1e5e9; background: #f8f9fa;\">\n <button class=\"cancel-btn\" style=\"padding: 10px 20px; background: #fff; border: 1px solid #ced4da; border-radius: 4px; cursor: pointer; font-size: 14px;\">Cancel</button>\n <button id=\"replace-btn\" style=\"padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;\" ${!urlValue && activeTab === 'url' ? 'disabled' : ''}>Replace</button>\n </div>\n `;\n };\n\n renderDialog();\n overlay.appendChild(dialog);\n document.body.appendChild(overlay);\n\n const closeDialog = () => document.body.removeChild(overlay);\n\n const replaceImage = () => {\n if (urlValue) {\n img.src = urlValue;\n closeDialog();\n }\n };\n\n const handleFileUpload = async (file: File) => {\n const progressDiv = dialog.querySelector('#upload-progress') as HTMLDivElement;\n const progressBar = dialog.querySelector('#progress-bar') as HTMLDivElement;\n const progressText = dialog.querySelector('#progress-text') as HTMLParagraphElement;\n\n if (progressDiv && progressBar && progressText) {\n progressDiv.style.display = 'block';\n\n let progress = 0;\n const interval = setInterval(() => {\n progress += Math.random() * 30;\n if (progress > 90) progress = 90;\n progressBar.style.width = `${progress}%`;\n }, 200);\n\n try {\n const reader = new FileReader();\n reader.onload = () => {\n clearInterval(interval);\n progressBar.style.width = '100%';\n progressText.textContent = '✅ Upload complete';\n \n setTimeout(() => {\n urlValue = reader.result as string;\n activeTab = 'url';\n renderDialog();\n attachEventHandlers();\n }, 500);\n };\n reader.readAsDataURL(file);\n } catch (error) {\n clearInterval(interval);\n progressText.textContent = '❌ Upload failed';\n }\n }\n };\n\n const attachEventHandlers = () => {\n const closeBtn = dialog.querySelector('.close-btn') as HTMLButtonElement;\n const cancelBtn = dialog.querySelector('.cancel-btn') as HTMLButtonElement;\n const replaceBtn = dialog.querySelector('#replace-btn') as HTMLButtonElement;\n const tabUpload = dialog.querySelector('.tab-upload') as HTMLButtonElement;\n const tabUrl = dialog.querySelector('.tab-url') as HTMLButtonElement;\n\n closeBtn?.addEventListener('click', closeDialog);\n cancelBtn?.addEventListener('click', closeDialog);\n replaceBtn?.addEventListener('click', replaceImage);\n\n tabUpload?.addEventListener('click', () => {\n activeTab = 'upload';\n renderDialog();\n attachEventHandlers();\n });\n\n tabUrl?.addEventListener('click', () => {\n activeTab = 'url';\n renderDialog();\n attachEventHandlers();\n });\n\n if (activeTab === 'upload') {\n const dropzone = dialog.querySelector('.dropzone') as HTMLDivElement;\n const fileInput = dialog.querySelector('#file-input') as HTMLInputElement;\n\n dropzone?.addEventListener('click', () => fileInput?.click());\n \n dropzone?.addEventListener('dragover', (e) => {\n e.preventDefault();\n dropzone.style.borderColor = '#007bff';\n dropzone.style.background = '#f0f8ff';\n });\n\n dropzone?.addEventListener('dragleave', () => {\n dropzone.style.borderColor = '#ced4da';\n dropzone.style.background = 'transparent';\n });\n\n dropzone?.addEventListener('drop', (e) => {\n e.preventDefault();\n dropzone.style.borderColor = '#ced4da';\n dropzone.style.background = 'transparent';\n const file = e.dataTransfer?.files[0];\n if (file) handleFileUpload(file);\n });\n\n fileInput?.addEventListener('change', (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (file) handleFileUpload(file);\n });\n }\n\n if (activeTab === 'url') {\n const urlInput = dialog.querySelector('#url-input') as HTMLInputElement;\n\n urlInput?.addEventListener('input', () => {\n urlValue = urlInput.value;\n renderDialog();\n attachEventHandlers();\n });\n }\n };\n\n attachEventHandlers();\n overlay.addEventListener('click', (e) => { if (e.target === overlay) closeDialog(); });\n};\n\nconst updatePosition = () => {\n if (!floatingToolbar || !selectedMedia) return;\n\n const toolbarHeight = floatingToolbar.offsetHeight || 40;\n const mediaTop = selectedMedia.offsetTop;\n const mediaLeft = selectedMedia.offsetLeft;\n const mediaWidth = selectedMedia.offsetWidth;\n\n // Position above the image, centered\n const top = mediaTop - toolbarHeight - 8;\n const left = mediaLeft + (mediaWidth / 2) - ((floatingToolbar.offsetWidth || 120) / 2);\n\n floatingToolbar.style.top = `${top}px`;\n floatingToolbar.style.left = `${left}px`;\n setTimeout(() => { \n if (floatingToolbar) floatingToolbar.style.display = \"flex\";\n },100);\n};\n\n// Show floating toolbar\nconst showFloatingToolbar = (media: HTMLImageElement | HTMLVideoElement) => {\n // Clean up existing toolbar\n if (floatingToolbar) {\n if ((floatingToolbar as any)._cleanup) {\n (floatingToolbar as any)._cleanup();\n }\n floatingToolbar.remove();\n }\n\n // Ensure parent has relative positioning\n const mediaParent = media.parentElement;\n if (mediaParent) {\n const originalPosition = mediaParent.style.position;\n if (!originalPosition || originalPosition === 'static') {\n mediaParent.style.position = 'relative';\n (mediaParent as any)._originalPosition = originalPosition; // Store for cleanup\n }\n\n floatingToolbar = document.createElement('div');\n floatingToolbar.className = 'media-floating-toolbar';\n floatingToolbar.style.cssText = `\n position: absolute;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 6px;\n box-shadow: 0 2px 12px rgba(0,0,0,0.15);\n gap: 2px;\n padding: 4px;\n z-index: 10000;\n pointer-events: auto;\n display: none;\n `;\n\n // Insert toolbar as first child of parent\n mediaParent.insertBefore(floatingToolbar, mediaParent.firstChild);\n\n // Position the toolbar\n updatePosition();\n }\n\n const buttonStyle = 'padding: 6px 8px; border: none; background: white; cursor: pointer; border-radius: 4px; transition: background 0.2s; display: flex; align-items: center; justify-content: center;';\n \n const isImage = media.tagName === 'IMG';\n const existingLink = (media as HTMLElement).closest('a');\n\n floatingToolbar.innerHTML = `\n <button class=\"btn-align-left\" title=\"Align Left\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"17\" y1=\"10\" x2=\"3\" y2=\"10\"></line><line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"></line><line x1=\"21\" y1=\"14\" x2=\"3\" y2=\"14\"></line><line x1=\"17\" y1=\"18\" x2=\"3\" y2=\"18\"></line></svg>\n </button>\n <button class=\"btn-align-center\" title=\"Align Center\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"18\" y1=\"10\" x2=\"6\" y2=\"10\"></line><line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"></line><line x1=\"21\" y1=\"14\" x2=\"3\" y2=\"14\"></line><line x1=\"18\" y1=\"18\" x2=\"6\" y2=\"18\"></line></svg>\n </button>\n <button class=\"btn-align-right\" title=\"Align Right\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"21\" y1=\"10\" x2=\"7\" y2=\"10\"></line><line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"></line><line x1=\"21\" y1=\"14\" x2=\"3\" y2=\"14\"></line><line x1=\"21\" y1=\"18\" x2=\"7\" y2=\"18\"></line></svg>\n </button>\n <div style=\"width: 1px; height: 20px; background: #dee2e6; margin: 0 2px;\"></div>\n ${isImage ? `\n <button class=\"btn-alt\" title=\"Edit Alt Text\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z\"></path></svg>\n </button>` : ''}\n <button class=\"btn-link\" title=\"${existingLink ? 'Edit/Remove Link' : 'Add Link'}\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"></path><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"></path></svg>\n </button>\n ${isImage ? `\n <button class=\"btn-replace\" title=\"Replace Image\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"></rect><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"></circle><polyline points=\"21 15 16 10 5 21\"></polyline></svg>\n </button>` : ''}\n <div style=\"width: 1px; height: 20px; background: #dee2e6; margin: 0 2px;\"></div>\n <button class=\"btn-remove\" title=\"Remove\" style=\"${buttonStyle}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"3 6 5 6 21 6\"></polyline><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"></path></svg>\n </button>\n `;\n\n\n\n // Position the toolbar after it's rendered\n setTimeout(() => {\n updatePosition();\n }, 0);\n\n // Add event listeners for repositioning\n const handleReposition = () => updatePosition();\n \n // Listen for scroll events on parent elements and window\n let currentElement: Element | null = selectedMedia.parentElement;\n while (currentElement) {\n currentElement.addEventListener('scroll', handleReposition);\n currentElement = currentElement.parentElement;\n }\n \n window.addEventListener('scroll', handleReposition);\n window.addEventListener('resize', handleReposition);\n \n // Store cleanup function\n (floatingToolbar as any)._cleanup = () => {\n let element: Element | null = selectedMedia?.parentElement;\n while (element) {\n element.removeEventListener('scroll', handleReposition);\n element = element.parentElement;\n }\n window.removeEventListener('scroll', handleReposition);\n window.removeEventListener('resize', handleReposition);\n };\n\n floatingToolbar.querySelectorAll('button').forEach(btn => {\n btn.addEventListener('mouseenter', () => {\n (btn as HTMLElement).style.background = '#f8f9fa';\n });\n btn.addEventListener('mouseleave', () => {\n (btn as HTMLElement).style.background = 'white';\n });\n });\n\n // Align Left\n floatingToolbar.querySelector('.btn-align-left')?.addEventListener('click', () => {\n media.style.display = 'block';\n media.style.marginLeft = '0';\n media.style.marginRight = 'auto';\n updatePosition();\n });\n\n // Align Center\n floatingToolbar.querySelector('.btn-align-center')?.addEventListener('click', () => {\n media.style.display = 'block';\n media.style.marginLeft = 'auto';\n media.style.marginRight = 'auto';\n updatePosition();\n });\n\n // Align Right\n floatingToolbar.querySelector('.btn-align-right')?.addEventListener('click', () => {\n media.style.display = 'block';\n media.style.marginLeft = 'auto';\n media.style.marginRight = '0';\n updatePosition();\n });\n\n // Edit Alt Text (Images only)\n floatingToolbar.querySelector('.btn-alt')?.addEventListener('click', () => {\n if (media.tagName === 'IMG') {\n showAltTextDialog(media as HTMLImageElement);\n }\n });\n\n // Add/Edit Link\n floatingToolbar.querySelector('.btn-link')?.addEventListener('click', () => {\n showLinkDialogForMedia(media);\n });\n\n // Replace Image\n floatingToolbar.querySelector('.btn-replace')?.addEventListener('click', () => {\n if (media.tagName === 'IMG') {\n showReplaceImageDialog(media as HTMLImageElement);\n }\n });\n\n floatingToolbar.querySelector('.btn-resize')?.addEventListener('click', () => {\n const width = prompt('Enter width in pixels:', String(media.width || media.offsetWidth));\n if (width && !isNaN(parseInt(width))) {\n const w = parseInt(width);\n media.style.width = `${w}px`;\n media.setAttribute('width', String(w));\n updateResizeHandles();\n updatePosition();\n }\n });\n\n floatingToolbar.querySelector('.btn-remove')?.addEventListener('click', () => {\n if (confirm('Remove this media?')) {\n media.remove();\n if (floatingToolbar) {\n if ((floatingToolbar as any)._cleanup) {\n (floatingToolbar as any)._cleanup();\n }\n floatingToolbar.remove();\n floatingToolbar = null;\n }\n selectedMedia = null;\n updateResizeHandles();\n }\n });\n\n // Add scroll and resize event listeners (matching resize handles approach)\n // Store cleanup function for later removal\n (floatingToolbar as any)._cleanup = () => {\n window.removeEventListener('scroll', updatePosition);\n window.removeEventListener('resize', updatePosition);\n };\n};\n\n// Initialize media manager function (moved outside conditional for plugin access)\nconst initMediaManager = (editorEl?: HTMLElement) => {\n // Store the editor element for scoping\n editorElement = editorEl || null;\n\n createResizeHandles();\n\n // Add click listener - global but scoped to this editor instance\n document.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n\n if (target.tagName === 'IMG' || target.tagName === 'VIDEO') {\n const media = target as HTMLImageElement | HTMLVideoElement;\n\n // Check if media is within this editor's contenteditable area\n let isInThisEditor = false;\n if (editorElement) {\n // For web component, check if media is within this editor element\n isInThisEditor = editorElement.contains(media);\n } else {\n // Fallback to global behavior\n isInThisEditor = !!media.closest('[contenteditable=\"true\"]');\n }\n\n if (isInThisEditor) {\n e.preventDefault();\n e.stopPropagation();\n selectedMedia = media;\n selectedMedia.style.display = 'block'; // Ensure block display for alignment\n showFloatingToolbar(media);\n updateResizeHandles();\n return;\n }\n }\n\n if (!target.closest('.btn-link, .btn-resize, .btn-remove')) {\n if (floatingToolbar && !target.closest('button')) {\n if ((floatingToolbar as any)._cleanup) {\n (floatingToolbar as any)._cleanup();\n }\n floatingToolbar.remove();\n floatingToolbar = null;\n \n // Restore parent position\n if (selectedMedia && selectedMedia.parentElement) {\n const parent = selectedMedia.parentElement;\n if ((parent as any)._originalPosition !== undefined) {\n parent.style.position = (parent as any)._originalPosition;\n delete (parent as any)._originalPosition;\n }\n }\n \n selectedMedia = null;\n updateResizeHandles();\n }\n }\n });\n\n resizeHandles.forEach(handle => {\n handle.addEventListener('mousedown', (e) => {\n if (!selectedMedia) return;\n e.preventDefault();\n e.stopPropagation();\n\n isResizing = true;\n currentHandle = handle.getAttribute('data-position');\n startX = e.clientX;\n startY = e.clientY;\n\n const rect = selectedMedia.getBoundingClientRect();\n startWidth = rect.width;\n startHeight = rect.height;\n aspectRatio = startWidth / startHeight;\n\n document.body.style.userSelect = 'none';\n document.body.style.cursor = `${currentHandle}-resize`;\n });\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isResizing || !selectedMedia || !currentHandle) return;\n\n const deltaX = e.clientX - startX;\n const deltaY = e.clientY - startY;\n\n let newWidth = startWidth;\n let newHeight = startHeight;\n\n switch (currentHandle) {\n case 'se':\n newWidth = startWidth + deltaX;\n newHeight = startHeight + deltaY;\n break;\n case 'sw':\n newWidth = startWidth - deltaX;\n newHeight = startHeight + deltaY;\n break;\n case 'ne':\n newWidth = startWidth + deltaX;\n newHeight = startHeight - deltaY;\n break;\n case 'nw':\n newWidth = startWidth - deltaX;\n newHeight = startHeight - deltaY;\n break;\n }\n\n if (Math.abs(deltaX) > Math.abs(deltaY)) {\n newHeight = newWidth / aspectRatio;\n } else {\n newWidth = newHeight * aspectRatio;\n }\n\n newWidth = Math.max(50, newWidth);\n newHeight = Math.max(50, newHeight);\n\n selectedMedia.style.width = `${newWidth}px`;\n selectedMedia.style.height = `${newHeight}px`;\n selectedMedia.setAttribute('width', String(Math.round(newWidth)));\n selectedMedia.setAttribute('height', String(Math.round(newHeight)));\n\n updateResizeHandles();\n updatePosition();\n });\n\n document.addEventListener('mouseup', () => {\n if (isResizing) {\n isResizing = false;\n currentHandle = null;\n document.body.style.userSelect = '';\n document.body.style.cursor = '';\n }\n });\n\n window.addEventListener('scroll', updateResizeHandles);\n window.addEventListener('resize', updateResizeHandles);\n};\n\n// Initialize media manager\nif (typeof window !== 'undefined' && !window.__mediaManagerInitialized) {\n window.__mediaManagerInitialized = true;\n\n // Call initMediaManager without parameters for global initialization\n initMediaManager();\n}\n\nexport const MediaManagerPlugin = (): Plugin => ({\n name: 'image',\n \n initialize: (config?: any) => {\n // Get the editor element from config (passed by web component)\n const editorEl = config?.editorElement;\n initMediaManager(editorEl);\n },\n \n toolbar: [\n {\n label: 'Image',\n command: 'insertImage',\n icon: '<svg width=\"24px\" height=\"24px\" viewBox=\"0 0 32 32\" enable-background=\"new 0 0 32 32\"><g><rect fill=\"none\" height=\"22\" stroke=\"#000000\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" stroke-width=\"2\" width=\"30\" x=\"1\" y=\"5\"></rect><polygon fill=\"none\" points=\"31,27 21,17 11,27\" stroke=\"#000000\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" stroke-width=\"2\"></polygon><polygon fill=\"none\" points=\"18,20 9,11 1,19 1,27 11,27\" stroke=\"#000000\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" stroke-width=\"2\"></polygon><circle cx=\"19\" cy=\"11\" fill=\"none\" r=\"2\" stroke=\"#000000\" stroke-linejoin=\"round\" stroke-miterlimit=\"10\" stroke-width=\"2\"></circle></g></svg>'\n },\n {\n label: 'Video',\n command: 'insertVideo',\n icon: '<svg width=\"24\" height=\"24\" focusable=\"false\"><path d=\"M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm4.8 2.6 5.6 4a.5.5 0 0 1 0 .8l-5.6 4A.5.5 0 0 1 9 16V8a.5.5 0 0 1 .8-.4Z\" fill-rule=\"nonzero\"></path></svg>'\n }\n ],\n \n commands: {\n insertImage: () => {\n showMediaDialog('image');\n return true;\n },\n \n insertVideo: () => {\n showMediaDialog('video');\n return true;\n }\n },\n \n keymap: {\n 'Mod-Shift-i': 'insertImage'\n }\n});\n"],"names":["savedSelection","selectedMedia","floatingToolbar","resizeHandles","isResizing","currentHandle","startX","startY","startWidth","startHeight","aspectRatio","editorElement","showMediaDialog","type","selection","overlay","dialog","activeTab","urlValue","widthValue","heightValue","altValue","renderDialog","closeDialog","insertMedia","mediaEl","handleFileUpload","file","progressDiv","progressBar","progressText","progress","interval","reader","attachEventHandlers","error","closeBtn","cancelBtn","insertBtn","tabUpload","tabUrl","dropzone","fileInput","e","_a","urlInput","altInput","widthInput","heightInput","createResizeHandles","pos","handle","updateResizeHandles","h","rect","positions","coord","showAltTextDialog","img","input","saveBtn","showLinkDialogForMedia","media","existingLink","currentHref","currentTarget","currentTitle","titleInput","targetCheckbox","removeLinkBtn","url","normalized","link","showFloatingToolbar","showReplaceImageDialog","replaceImage","replaceBtn","updatePosition","toolbarHeight","mediaTop","mediaLeft","mediaWidth","top","left","_b","_c","_d","_e","_f","_g","_h","mediaParent","originalPosition","buttonStyle","isImage","handleReposition","currentElement","element","btn","width","w","initMediaManager","editorEl","target","isInThisEditor","parent","deltaX","deltaY","newWidth","newHeight","MediaManagerPlugin","config"],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ const E = {
2
+ USER: {
3
+ name: "User",
4
+ tags: [
5
+ { key: "first_name", label: "First Name", category: "User", preview: "John" },
6
+ { key: "last_name", label: "Last Name", category: "User", preview: "Doe" },
7
+ { key: "email", label: "Email", category: "User", preview: "john@example.com" },
8
+ { key: "phone", label: "Phone", category: "User", preview: "+1-555-1234" },
9
+ { key: "full_name", label: "Full Name", category: "User", preview: "John Doe" },
10
+ { key: "username", label: "Username", category: "User", preview: "johndoe" }
11
+ ]
12
+ },
13
+ COMPANY: {
14
+ name: "Company",
15
+ tags: [
16
+ { key: "company_name", label: "Company Name", category: "Company", preview: "Acme Corp" },
17
+ { key: "company_address", label: "Company Address", category: "Company", preview: "123 Main St" },
18
+ { key: "company_phone", label: "Company Phone", category: "Company", preview: "+1-555-0000" },
19
+ { key: "company_email", label: "Company Email", category: "Company", preview: "info@acme.com" }
20
+ ]
21
+ },
22
+ DATE: {
23
+ name: "Date",
24
+ tags: [
25
+ { key: "today", label: "Today", category: "Date", preview: (/* @__PURE__ */ new Date()).toLocaleDateString() },
26
+ { key: "tomorrow", label: "Tomorrow", category: "Date", preview: new Date(Date.now() + 864e5).toLocaleDateString() },
27
+ { key: "next_week", label: "Next Week", category: "Date", preview: new Date(Date.now() + 6048e5).toLocaleDateString() }
28
+ ]
29
+ },
30
+ CUSTOM: {
31
+ name: "Custom",
32
+ tags: []
33
+ }
34
+ };
35
+ let L = null, r = null;
36
+ function T(c) {
37
+ const s = L;
38
+ if (!s) return;
39
+ const l = window.getSelection();
40
+ if (!l) return;
41
+ l.removeAllRanges(), l.addRange(s);
42
+ const C = `merge-tag-${c.key}-${Date.now()}`, t = document.createElement("span");
43
+ t.className = "rte-merge-tag", t.id = C, t.setAttribute("contenteditable", "false"), t.setAttribute("data-key", c.key), t.setAttribute("data-category", c.category), t.setAttribute("aria-label", `Merge tag: ${c.label}`), t.textContent = `{{ ${c.label} }}`, t.style.cssText = "background-color: #e3f2fd; border: 1px solid #bbdefb; border-radius: 3px; padding: 2px 6px; margin: 0 2px; display: inline-block; white-space: nowrap; font-weight: 500; color: #1976d2; cursor: pointer; user-select: none;";
44
+ try {
45
+ s.deleteContents(), s.insertNode(t), s.setStartAfter(t), s.setEndAfter(t), l.removeAllRanges(), l.addRange(s);
46
+ const i = t.closest('[contenteditable="true"]');
47
+ i && i.dispatchEvent(new Event("input", { bubbles: !0 }));
48
+ } catch (i) {
49
+ console.error("Failed to insert merge tag:", i);
50
+ }
51
+ }
52
+ function R() {
53
+ var A;
54
+ const c = window.getSelection();
55
+ c && c.rangeCount > 0 && (L = c.getRangeAt(0).cloneRange());
56
+ let s = "USER", l = "", C = E.USER.tags;
57
+ r = C[0] || null;
58
+ const t = document.createElement("div");
59
+ t.className = "rte-dialog-overlay", t.style.cssText = "position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 10000;";
60
+ const i = document.createElement("div");
61
+ i.className = "rte-dialog rte-merge-tag-dialog", i.style.cssText = "background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.15); width: 500px; max-width: 90vw; max-height: 600px; overflow: hidden; display: flex; flex-direction: column;";
62
+ const f = document.createElement("div");
63
+ f.className = "rte-dialog-header", f.style.cssText = "padding: 16px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;", f.innerHTML = `
64
+ <h2 style="margin: 0; font-size: 18px; font-weight: 600;">Insert Merge Tag</h2>
65
+ <button class="rte-dialog-close" style="background: none; border: none; font-size: 24px; cursor: pointer; color: #999; padding: 0; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;" aria-label="Close">✕</button>
66
+ `;
67
+ const y = document.createElement("div");
68
+ y.className = "rte-dialog-body", y.style.cssText = "padding: 16px; overflow-y: auto; flex: 1;";
69
+ const d = document.createElement("input");
70
+ d.type = "text", d.className = "rte-input", d.placeholder = "Search merge tags...", d.setAttribute("aria-label", "Search merge tags"), d.style.cssText = "width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; box-sizing: border-box; margin-bottom: 12px;", y.appendChild(d);
71
+ const v = document.createElement("div");
72
+ v.className = "rte-tabs", v.style.cssText = "display: flex; gap: 8px; margin-bottom: 12px; border-bottom: 2px solid #eee;";
73
+ const N = Object.entries(E).map(([a, e]) => ({ key: a, name: e.name }));
74
+ N.forEach((a) => {
75
+ const e = document.createElement("button");
76
+ e.className = "rte-tab", e.textContent = a.name, e.setAttribute("aria-label", `${a.name} category`), e.style.cssText = "padding: 8px 12px; background: none; border: none; cursor: pointer; border-bottom: 3px solid transparent; color: #666; font-weight: 500; transition: all 0.2s;", a.key === s && (e.classList.add("active"), e.style.color = "#1976d2", e.style.borderBottomColor = "#1976d2"), e.addEventListener("click", () => {
77
+ s = a.key, l = "", d.value = "", M(), k();
78
+ }), e.addEventListener("mouseenter", () => {
79
+ e.style.color = "#333";
80
+ }), e.addEventListener("mouseleave", () => {
81
+ e.classList.contains("active") || (e.style.color = "#666");
82
+ }), v.appendChild(e);
83
+ }), y.appendChild(v);
84
+ const u = document.createElement("div");
85
+ u.className = "rte-merge-tag-list", u.style.cssText = "border: 1px solid #ddd; border-radius: 4px; max-height: 300px; overflow-y: auto; margin-bottom: 12px;", y.appendChild(u);
86
+ const x = document.createElement("div");
87
+ x.className = "rte-merge-tag-preview", x.style.cssText = "padding: 8px; background-color: #f5f5f5; border-radius: 4px; font-family: monospace; font-size: 12px;", y.appendChild(x);
88
+ function M() {
89
+ v.querySelectorAll(".rte-tab").forEach((e, o) => {
90
+ N[o].key === s ? (e.classList.add("active"), e.style.color = "#1976d2", e.style.borderBottomColor = "#1976d2") : (e.classList.remove("active"), e.style.color = "#666", e.style.borderBottomColor = "transparent");
91
+ });
92
+ }
93
+ function k() {
94
+ const a = E[s];
95
+ let e = a ? a.tags : [];
96
+ if (l.trim() && (e = e.filter(
97
+ (o) => o.label.toLowerCase().includes(l.toLowerCase()) || o.key.toLowerCase().includes(l.toLowerCase())
98
+ )), C = e, r = e[0] || null, u.innerHTML = "", e.length === 0) {
99
+ const o = document.createElement("div");
100
+ o.className = "rte-empty-state", o.textContent = "No merge tags found", o.style.cssText = "padding: 24px; text-align: center; color: #999;", u.appendChild(o);
101
+ } else
102
+ e.forEach((o, S) => {
103
+ const n = document.createElement("div");
104
+ n.className = "rte-merge-tag-item", n.setAttribute("data-tag-key", o.key), n.style.cssText = "padding: 8px 12px; border-bottom: 1px solid #f0f0f0; cursor: pointer; transition: background-color 0.2s;", S === 0 && (n.classList.add("selected"), n.style.backgroundColor = "#f5f5f5");
105
+ const w = document.createElement("div");
106
+ if (w.className = "tag-label", w.textContent = o.label, w.style.cssText = "font-weight: 600; color: #333;", n.appendChild(w), o.preview) {
107
+ const g = document.createElement("div");
108
+ g.className = "tag-preview", g.textContent = o.preview, g.style.cssText = "font-size: 12px; color: #999; margin-top: 2px;", n.appendChild(g);
109
+ }
110
+ if (o.description) {
111
+ const g = document.createElement("div");
112
+ g.className = "tag-description", g.textContent = o.description, g.style.cssText = "font-size: 12px; color: #aaa; margin-top: 2px;", n.appendChild(g);
113
+ }
114
+ n.addEventListener("click", () => {
115
+ r = o, U(), D();
116
+ }), n.addEventListener("dblclick", () => {
117
+ T(o), b();
118
+ }), n.addEventListener("mouseenter", () => {
119
+ n.style.backgroundColor = "#f5f5f5";
120
+ }), n.addEventListener("mouseleave", () => {
121
+ n.classList.contains("selected") || (n.style.backgroundColor = "");
122
+ }), u.appendChild(n);
123
+ });
124
+ D();
125
+ }
126
+ function U() {
127
+ u.querySelectorAll(".rte-merge-tag-item").forEach((e) => {
128
+ e.getAttribute("data-tag-key") === (r == null ? void 0 : r.key) ? (e.classList.add("selected"), e.style.backgroundColor = "#f5f5f5") : (e.classList.remove("selected"), e.style.backgroundColor = "");
129
+ });
130
+ }
131
+ function D() {
132
+ r ? (x.innerHTML = `<strong>Preview:</strong> {{ ${r.label} }}`, x.style.display = "block") : x.style.display = "none";
133
+ }
134
+ d.addEventListener("input", (a) => {
135
+ l = a.target.value, k();
136
+ }), d.addEventListener("keydown", (a) => {
137
+ a.key === "Enter" && r ? (T(r), b()) : a.key === "Escape" && b();
138
+ });
139
+ const h = document.createElement("div");
140
+ h.className = "rte-dialog-footer", h.style.cssText = "padding: 12px 16px; border-top: 1px solid #eee; display: flex; gap: 8px; justify-content: flex-end;";
141
+ const p = document.createElement("button");
142
+ p.className = "rte-button-secondary", p.textContent = "Cancel", p.style.cssText = "padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; cursor: pointer; background-color: #f5f5f5; color: #333; transition: all 0.2s;", p.addEventListener("click", b), p.addEventListener("mouseenter", () => {
143
+ p.style.backgroundColor = "#eeeeee";
144
+ }), p.addEventListener("mouseleave", () => {
145
+ p.style.backgroundColor = "#f5f5f5";
146
+ });
147
+ const m = document.createElement("button");
148
+ m.className = "rte-button-primary", m.textContent = "Insert", m.style.cssText = "padding: 8px 16px; border: none; border-radius: 4px; font-size: 14px; cursor: pointer; background-color: #1976d2; color: white; transition: all 0.2s;", m.addEventListener("click", () => {
149
+ r && (T(r), b());
150
+ }), m.addEventListener("mouseenter", () => {
151
+ m.style.backgroundColor = "#1565c0";
152
+ }), m.addEventListener("mouseleave", () => {
153
+ m.style.backgroundColor = "#1976d2";
154
+ }), h.appendChild(p), h.appendChild(m), i.appendChild(f), i.appendChild(y), i.appendChild(h), t.appendChild(i);
155
+ function b() {
156
+ t.remove(), L = null, r = null;
157
+ }
158
+ (A = f.querySelector(".rte-dialog-close")) == null || A.addEventListener("click", b), t.addEventListener("click", (a) => {
159
+ a.target === t && b();
160
+ }), document.body.appendChild(t), k(), setTimeout(() => d.focus(), 100);
161
+ }
162
+ const z = () => ({
163
+ name: "mergeTag",
164
+ toolbar: [
165
+ {
166
+ label: "Merge Tag",
167
+ command: "insertMergeTag",
168
+ icon: "{{ }}"
169
+ }
170
+ ],
171
+ commands: {
172
+ insertMergeTag: () => (R(), !0)
173
+ }
174
+ });
175
+ export {
176
+ z as MergeTagPlugin
177
+ };
178
+ //# sourceMappingURL=MergeTagPlugin.native-CrxyThyn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MergeTagPlugin.native-CrxyThyn.mjs","sources":["../../plugins/merge-tag/src/MergeTagPlugin.native.ts"],"sourcesContent":["import type { Plugin } from '@editora/core';\n\n/**\n * MergeTagPlugin - Native implementation\n * \n * Features:\n * - Category tabs (User, Company, Date, Custom)\n * - Search and filter\n * - Tag preview pane\n * - Keyboard navigation (Enter to insert, Escape to close)\n * - Double-click to insert\n * - Accessible dialog\n * - Non-editable inline tags\n * - Styled merge tags matching React version\n */\n\ninterface MergeTag {\n key: string;\n label: string;\n category: string;\n preview?: string;\n description?: string;\n}\n\nconst MERGE_TAG_CATEGORIES = {\n USER: {\n name: 'User',\n tags: [\n { key: 'first_name', label: 'First Name', category: 'User', preview: 'John' },\n { key: 'last_name', label: 'Last Name', category: 'User', preview: 'Doe' },\n { key: 'email', label: 'Email', category: 'User', preview: 'john@example.com' },\n { key: 'phone', label: 'Phone', category: 'User', preview: '+1-555-1234' },\n { key: 'full_name', label: 'Full Name', category: 'User', preview: 'John Doe' },\n { key: 'username', label: 'Username', category: 'User', preview: 'johndoe' }\n ]\n },\n COMPANY: {\n name: 'Company',\n tags: [\n { key: 'company_name', label: 'Company Name', category: 'Company', preview: 'Acme Corp' },\n { key: 'company_address', label: 'Company Address', category: 'Company', preview: '123 Main St' },\n { key: 'company_phone', label: 'Company Phone', category: 'Company', preview: '+1-555-0000' },\n { key: 'company_email', label: 'Company Email', category: 'Company', preview: 'info@acme.com' }\n ]\n },\n DATE: {\n name: 'Date',\n tags: [\n { key: 'today', label: 'Today', category: 'Date', preview: new Date().toLocaleDateString() },\n { key: 'tomorrow', label: 'Tomorrow', category: 'Date', preview: new Date(Date.now() + 86400000).toLocaleDateString() },\n { key: 'next_week', label: 'Next Week', category: 'Date', preview: new Date(Date.now() + 604800000).toLocaleDateString() }\n ]\n },\n CUSTOM: {\n name: 'Custom',\n tags: []\n }\n};\n\nlet savedSelection: Range | null = null;\nlet selectedTag: MergeTag | null = null;\n\nfunction insertMergeTag(tag: MergeTag) {\n const range = savedSelection;\n if (!range) return;\n\n const selection = window.getSelection();\n if (!selection) return;\n\n selection.removeAllRanges();\n selection.addRange(range);\n\n const tagId = `merge-tag-${tag.key}-${Date.now()}`;\n const span = document.createElement('span');\n span.className = 'rte-merge-tag';\n span.id = tagId;\n span.setAttribute('contenteditable', 'false');\n span.setAttribute('data-key', tag.key);\n span.setAttribute('data-category', tag.category);\n span.setAttribute('aria-label', `Merge tag: ${tag.label}`);\n span.textContent = `{{ ${tag.label} }}`;\n span.style.cssText = 'background-color: #e3f2fd; border: 1px solid #bbdefb; border-radius: 3px; padding: 2px 6px; margin: 0 2px; display: inline-block; white-space: nowrap; font-weight: 500; color: #1976d2; cursor: pointer; user-select: none;';\n\n try {\n range.deleteContents();\n range.insertNode(span);\n \n // Move cursor after the tag\n range.setStartAfter(span);\n range.setEndAfter(span);\n selection.removeAllRanges();\n selection.addRange(range);\n\n // Trigger input event\n const editor = span.closest('[contenteditable=\"true\"]');\n if (editor) {\n editor.dispatchEvent(new Event('input', { bubbles: true }));\n }\n } catch (error) {\n console.error('Failed to insert merge tag:', error);\n }\n}\n\nfunction showMergeTagDialog() {\n // Save current selection\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n savedSelection = selection.getRangeAt(0).cloneRange();\n }\n\n let currentCategory = 'USER';\n let searchTerm = '';\n let filteredTags: MergeTag[] = MERGE_TAG_CATEGORIES.USER.tags;\n selectedTag = filteredTags[0] || null;\n\n // Create overlay\n const overlay = document.createElement('div');\n overlay.className = 'rte-dialog-overlay';\n overlay.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 10000;';\n\n // Create dialog\n const dialog = document.createElement('div');\n dialog.className = 'rte-dialog rte-merge-tag-dialog';\n dialog.style.cssText = 'background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.15); width: 500px; max-width: 90vw; max-height: 600px; overflow: hidden; display: flex; flex-direction: column;';\n\n // Header\n const header = document.createElement('div');\n header.className = 'rte-dialog-header';\n header.style.cssText = 'padding: 16px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;';\n header.innerHTML = `\n <h2 style=\"margin: 0; font-size: 18px; font-weight: 600;\">Insert Merge Tag</h2>\n <button class=\"rte-dialog-close\" style=\"background: none; border: none; font-size: 24px; cursor: pointer; color: #999; padding: 0; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;\" aria-label=\"Close\">✕</button>\n `;\n\n // Body\n const body = document.createElement('div');\n body.className = 'rte-dialog-body';\n body.style.cssText = 'padding: 16px; overflow-y: auto; flex: 1;';\n\n // Search input\n const searchInput = document.createElement('input');\n searchInput.type = 'text';\n searchInput.className = 'rte-input';\n searchInput.placeholder = 'Search merge tags...';\n searchInput.setAttribute('aria-label', 'Search merge tags');\n searchInput.style.cssText = 'width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; box-sizing: border-box; margin-bottom: 12px;';\n body.appendChild(searchInput);\n\n // Category tabs\n const tabsContainer = document.createElement('div');\n tabsContainer.className = 'rte-tabs';\n tabsContainer.style.cssText = 'display: flex; gap: 8px; margin-bottom: 12px; border-bottom: 2px solid #eee;';\n\n const categories = Object.entries(MERGE_TAG_CATEGORIES).map(([key, value]) => ({ key, name: value.name }));\n categories.forEach(cat => {\n const tab = document.createElement('button');\n tab.className = 'rte-tab';\n tab.textContent = cat.name;\n tab.setAttribute('aria-label', `${cat.name} category`);\n tab.style.cssText = 'padding: 8px 12px; background: none; border: none; cursor: pointer; border-bottom: 3px solid transparent; color: #666; font-weight: 500; transition: all 0.2s;';\n \n if (cat.key === currentCategory) {\n tab.classList.add('active');\n tab.style.color = '#1976d2';\n tab.style.borderBottomColor = '#1976d2';\n }\n\n tab.addEventListener('click', () => {\n currentCategory = cat.key;\n searchTerm = '';\n searchInput.value = '';\n updateTabs();\n updateTagList();\n });\n\n tab.addEventListener('mouseenter', () => {\n tab.style.color = '#333';\n });\n\n tab.addEventListener('mouseleave', () => {\n if (!tab.classList.contains('active')) {\n tab.style.color = '#666';\n }\n });\n\n tabsContainer.appendChild(tab);\n });\n body.appendChild(tabsContainer);\n\n // Tag list\n const tagList = document.createElement('div');\n tagList.className = 'rte-merge-tag-list';\n tagList.style.cssText = 'border: 1px solid #ddd; border-radius: 4px; max-height: 300px; overflow-y: auto; margin-bottom: 12px;';\n body.appendChild(tagList);\n\n // Preview pane\n const previewPane = document.createElement('div');\n previewPane.className = 'rte-merge-tag-preview';\n previewPane.style.cssText = 'padding: 8px; background-color: #f5f5f5; border-radius: 4px; font-family: monospace; font-size: 12px;';\n body.appendChild(previewPane);\n\n function updateTabs() {\n const tabs = tabsContainer.querySelectorAll('.rte-tab');\n tabs.forEach((tab, index) => {\n const cat = categories[index];\n if (cat.key === currentCategory) {\n tab.classList.add('active');\n (tab as HTMLElement).style.color = '#1976d2';\n (tab as HTMLElement).style.borderBottomColor = '#1976d2';\n } else {\n tab.classList.remove('active');\n (tab as HTMLElement).style.color = '#666';\n (tab as HTMLElement).style.borderBottomColor = 'transparent';\n }\n });\n }\n\n function updateTagList() {\n const categoryData = MERGE_TAG_CATEGORIES[currentCategory as keyof typeof MERGE_TAG_CATEGORIES];\n let tags = categoryData ? categoryData.tags : [];\n\n // Filter by search\n if (searchTerm.trim()) {\n tags = tags.filter(tag =>\n tag.label.toLowerCase().includes(searchTerm.toLowerCase()) ||\n tag.key.toLowerCase().includes(searchTerm.toLowerCase())\n );\n }\n\n filteredTags = tags;\n selectedTag = tags[0] || null;\n\n // Clear and rebuild tag list\n tagList.innerHTML = '';\n\n if (tags.length === 0) {\n const emptyState = document.createElement('div');\n emptyState.className = 'rte-empty-state';\n emptyState.textContent = 'No merge tags found';\n emptyState.style.cssText = 'padding: 24px; text-align: center; color: #999;';\n tagList.appendChild(emptyState);\n } else {\n tags.forEach((tag, index) => {\n const tagItem = document.createElement('div');\n tagItem.className = 'rte-merge-tag-item';\n tagItem.setAttribute('data-tag-key', tag.key);\n tagItem.style.cssText = 'padding: 8px 12px; border-bottom: 1px solid #f0f0f0; cursor: pointer; transition: background-color 0.2s;';\n\n if (index === 0) {\n tagItem.classList.add('selected');\n tagItem.style.backgroundColor = '#f5f5f5';\n }\n\n const labelDiv = document.createElement('div');\n labelDiv.className = 'tag-label';\n labelDiv.textContent = tag.label;\n labelDiv.style.cssText = 'font-weight: 600; color: #333;';\n tagItem.appendChild(labelDiv);\n\n if (tag.preview) {\n const previewDiv = document.createElement('div');\n previewDiv.className = 'tag-preview';\n previewDiv.textContent = tag.preview;\n previewDiv.style.cssText = 'font-size: 12px; color: #999; margin-top: 2px;';\n tagItem.appendChild(previewDiv);\n }\n\n if (tag.description) {\n const descDiv = document.createElement('div');\n descDiv.className = 'tag-description';\n descDiv.textContent = tag.description;\n descDiv.style.cssText = 'font-size: 12px; color: #aaa; margin-top: 2px;';\n tagItem.appendChild(descDiv);\n }\n\n tagItem.addEventListener('click', () => {\n selectedTag = tag;\n updateTagSelection();\n updatePreview();\n });\n\n tagItem.addEventListener('dblclick', () => {\n insertMergeTag(tag);\n closeDialog();\n });\n\n tagItem.addEventListener('mouseenter', () => {\n tagItem.style.backgroundColor = '#f5f5f5';\n });\n\n tagItem.addEventListener('mouseleave', () => {\n if (!tagItem.classList.contains('selected')) {\n tagItem.style.backgroundColor = '';\n }\n });\n\n tagList.appendChild(tagItem);\n });\n }\n\n updatePreview();\n }\n\n function updateTagSelection() {\n const items = tagList.querySelectorAll('.rte-merge-tag-item');\n items.forEach(item => {\n const key = item.getAttribute('data-tag-key');\n if (key === selectedTag?.key) {\n item.classList.add('selected');\n (item as HTMLElement).style.backgroundColor = '#f5f5f5';\n } else {\n item.classList.remove('selected');\n (item as HTMLElement).style.backgroundColor = '';\n }\n });\n }\n\n function updatePreview() {\n if (selectedTag) {\n previewPane.innerHTML = `<strong>Preview:</strong> {{ ${selectedTag.label} }}`;\n previewPane.style.display = 'block';\n } else {\n previewPane.style.display = 'none';\n }\n }\n\n // Search functionality\n searchInput.addEventListener('input', (e) => {\n searchTerm = (e.target as HTMLInputElement).value;\n updateTagList();\n });\n\n // Keyboard navigation\n searchInput.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && selectedTag) {\n insertMergeTag(selectedTag);\n closeDialog();\n } else if (e.key === 'Escape') {\n closeDialog();\n }\n });\n\n // Footer\n const footer = document.createElement('div');\n footer.className = 'rte-dialog-footer';\n footer.style.cssText = 'padding: 12px 16px; border-top: 1px solid #eee; display: flex; gap: 8px; justify-content: flex-end;';\n\n const cancelBtn = document.createElement('button');\n cancelBtn.className = 'rte-button-secondary';\n cancelBtn.textContent = 'Cancel';\n cancelBtn.style.cssText = 'padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; cursor: pointer; background-color: #f5f5f5; color: #333; transition: all 0.2s;';\n cancelBtn.addEventListener('click', closeDialog);\n cancelBtn.addEventListener('mouseenter', () => {\n cancelBtn.style.backgroundColor = '#eeeeee';\n });\n cancelBtn.addEventListener('mouseleave', () => {\n cancelBtn.style.backgroundColor = '#f5f5f5';\n });\n\n const insertBtn = document.createElement('button');\n insertBtn.className = 'rte-button-primary';\n insertBtn.textContent = 'Insert';\n insertBtn.style.cssText = 'padding: 8px 16px; border: none; border-radius: 4px; font-size: 14px; cursor: pointer; background-color: #1976d2; color: white; transition: all 0.2s;';\n insertBtn.addEventListener('click', () => {\n if (selectedTag) {\n insertMergeTag(selectedTag);\n closeDialog();\n }\n });\n insertBtn.addEventListener('mouseenter', () => {\n insertBtn.style.backgroundColor = '#1565c0';\n });\n insertBtn.addEventListener('mouseleave', () => {\n insertBtn.style.backgroundColor = '#1976d2';\n });\n\n footer.appendChild(cancelBtn);\n footer.appendChild(insertBtn);\n\n // Assemble dialog\n dialog.appendChild(header);\n dialog.appendChild(body);\n dialog.appendChild(footer);\n overlay.appendChild(dialog);\n\n // Close handlers\n function closeDialog() {\n overlay.remove();\n savedSelection = null;\n selectedTag = null;\n }\n\n header.querySelector('.rte-dialog-close')?.addEventListener('click', closeDialog);\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) closeDialog();\n });\n\n // Add to document\n document.body.appendChild(overlay);\n\n // Initialize\n updateTagList();\n\n // Focus search\n setTimeout(() => searchInput.focus(), 100);\n}\n\nexport const MergeTagPlugin = (): Plugin => ({\n name: 'mergeTag',\n \n toolbar: [\n {\n label: 'Merge Tag',\n command: 'insertMergeTag',\n icon: '{{ }}',\n }\n ],\n \n commands: {\n insertMergeTag: () => {\n showMergeTagDialog();\n return true;\n }\n }\n});\n"],"names":["MERGE_TAG_CATEGORIES","savedSelection","selectedTag","insertMergeTag","tag","range","selection","tagId","span","editor","error","showMergeTagDialog","_a","currentCategory","searchTerm","filteredTags","overlay","dialog","header","body","searchInput","tabsContainer","categories","key","value","cat","tab","updateTabs","updateTagList","tagList","previewPane","index","categoryData","tags","emptyState","tagItem","labelDiv","previewDiv","descDiv","updateTagSelection","updatePreview","closeDialog","item","e","footer","cancelBtn","insertBtn","MergeTagPlugin"],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ let c = null;
2
+ const b = () => {
3
+ c || (c = document.createElement("style"), c.textContent = `
4
+ .rte-page-break {
5
+ display: block;
6
+ position: relative;
7
+ height: 12px;
8
+ margin: 8px 0;
9
+ background: linear-gradient(90deg, #ccc 0%, transparent 100%);
10
+ border-top: 2px dashed #999;
11
+ border-bottom: none;
12
+ cursor: pointer;
13
+ user-select: none;
14
+ transition: all 0.2s ease;
15
+ outline: none;
16
+ -webkit-user-select: none;
17
+ -moz-user-select: none;
18
+ -ms-user-select: none;
19
+ }
20
+
21
+ .rte-page-break::before {
22
+ content: '⎙ PAGE BREAK';
23
+ position: absolute;
24
+ top: -12px;
25
+ left: 0;
26
+ font-size: 10px;
27
+ font-weight: bold;
28
+ color: #666;
29
+ background: white;
30
+ padding: 2px 6px;
31
+ letter-spacing: 0.5px;
32
+ opacity: 0.7;
33
+ pointer-events: none;
34
+ }
35
+
36
+ .rte-page-break:hover {
37
+ background: linear-gradient(90deg, #999 0%, transparent 100%);
38
+ border-top-color: #666;
39
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
40
+ }
41
+
42
+ .rte-page-break:hover::before {
43
+ opacity: 1;
44
+ color: #333;
45
+ }
46
+
47
+ .rte-page-break:focus,
48
+ .rte-page-break:focus-visible,
49
+ .rte-page-break-selected {
50
+ outline: 2px solid #0066cc;
51
+ outline-offset: -2px;
52
+ border-top-color: #0066cc;
53
+ background: linear-gradient(90deg, #0066cc 0%, transparent 100%);
54
+ }
55
+
56
+ .rte-page-break * {
57
+ user-select: none;
58
+ }
59
+
60
+ @media print {
61
+ .rte-page-break {
62
+ display: block;
63
+ height: 0;
64
+ margin: 0;
65
+ background: none;
66
+ border: none;
67
+ page-break-after: always;
68
+ }
69
+
70
+ .rte-page-break::before {
71
+ display: none;
72
+ }
73
+ }
74
+ `, document.head.appendChild(c));
75
+ }, u = (e) => {
76
+ const i = ["SPAN", "A", "STRONG", "EM", "B", "I", "U", "SUP", "SUB", "CODE"];
77
+ let n = e.nodeType === Node.TEXT_NODE ? e.parentElement : e;
78
+ for (; n && !n.hasAttribute("contenteditable"); ) {
79
+ if (i.includes(n.tagName))
80
+ return !0;
81
+ n = n.parentElement;
82
+ }
83
+ return !1;
84
+ }, m = (e) => {
85
+ const i = ["DIV", "P", "BLOCKQUOTE", "PRE", "H1", "H2", "H3", "H4", "H5", "H6", "LI", "TD", "TH"];
86
+ let n = e;
87
+ for (; n; ) {
88
+ if (n.nodeType === Node.ELEMENT_NODE) {
89
+ const s = n;
90
+ if (i.includes(s.tagName))
91
+ return s;
92
+ }
93
+ n = n.parentNode;
94
+ }
95
+ return null;
96
+ }, k = (e) => {
97
+ let i = e.nextElementSibling;
98
+ for (; i && i.classList.contains("rte-page-break"); )
99
+ i.remove(), i = e.nextElementSibling;
100
+ let n = e.previousElementSibling;
101
+ for (; n && n.classList.contains("rte-page-break"); ) {
102
+ const s = n;
103
+ n = n.previousElementSibling, s.remove();
104
+ }
105
+ }, f = () => {
106
+ var p, d;
107
+ const e = window.getSelection();
108
+ if (!e || e.rangeCount === 0) return !1;
109
+ const n = e.getRangeAt(0).commonAncestorContainer;
110
+ if (u(n))
111
+ return console.warn("Page breaks cannot be inserted in inline contexts"), !1;
112
+ const s = m(n);
113
+ if (!s)
114
+ return console.warn("No block element found for page break insertion"), !1;
115
+ const t = document.createElement("div");
116
+ t.className = "rte-page-break", t.setAttribute("data-page-break", "true"), t.setAttribute("data-type", "page-break"), t.setAttribute("contenteditable", "false"), t.setAttribute("tabindex", "0"), t.setAttribute("role", "separator"), t.setAttribute("aria-label", "Page break"), t.addEventListener("click", (r) => {
117
+ r.preventDefault(), r.stopPropagation(), t.focus();
118
+ const a = document.createRange();
119
+ a.selectNode(t), e.removeAllRanges(), e.addRange(a);
120
+ }), t.addEventListener("keydown", (r) => {
121
+ if (r.key === "Delete" || r.key === "Backspace") {
122
+ r.preventDefault();
123
+ const a = t.nextElementSibling || t.previousElementSibling;
124
+ if (t.remove(), a) {
125
+ const o = document.createRange();
126
+ o.selectNode(a), e.removeAllRanges(), e.addRange(o);
127
+ }
128
+ } else if (r.key === "ArrowDown" || r.key === "ArrowRight") {
129
+ r.preventDefault();
130
+ const a = t.nextElementSibling;
131
+ if (a) {
132
+ const o = document.createRange();
133
+ o.setStart(a, 0), o.collapse(!0), e.removeAllRanges(), e.addRange(o);
134
+ }
135
+ } else if (r.key === "ArrowUp" || r.key === "ArrowLeft") {
136
+ r.preventDefault();
137
+ const a = t.previousElementSibling;
138
+ if (a) {
139
+ const o = document.createRange();
140
+ o.selectNodeContents(a), o.collapse(!1), e.removeAllRanges(), e.addRange(o);
141
+ }
142
+ }
143
+ }), (p = s.parentNode) == null || p.insertBefore(t, s.nextSibling), k(t);
144
+ const l = document.createRange(), g = t.nextSibling;
145
+ if (g)
146
+ l.setStart(g, 0);
147
+ else {
148
+ const r = document.createElement("p");
149
+ r.innerHTML = "<br>", (d = t.parentNode) == null || d.insertBefore(r, t.nextSibling), l.setStart(r, 0);
150
+ }
151
+ return l.collapse(!0), e.removeAllRanges(), e.addRange(l), !0;
152
+ }, C = () => (b(), {
153
+ name: "pageBreak",
154
+ toolbar: [
155
+ {
156
+ label: "Page Break",
157
+ command: "insertPageBreak",
158
+ icon: '<svg fill="#000000" width="24px" height="24px" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M1,6 L3,6 C3.55228475,6 4,6.44771525 4,7 C4,7.55228475 3.55228475,8 3,8 L1,8 C0.44771525,8 0,7.55228475 0,7 C0,6.44771525 0.44771525,6 1,6 Z M11,6 L13,6 C13.5522847,6 14,6.44771525 14,7 C14,7.55228475 13.5522847,8 13,8 L11,8 C10.4477153,8 10,7.55228475 10,7 C10,6.44771525 10.4477153,6 11,6 Z M6,6 L8,6 C8.55228475,6 9,6.44771525 9,7 C9,7.55228475 8.55228475,8 8,8 L6,8 C5.44771525,8 5,7.55228475 5,7 C5,6.44771525 5.44771525,6 6,6 Z M0,1 C0,0.44771525 0.44771525,-2.26485497e-13 1,-2.26485497e-13 C1.55228475,-2.26485497e-13 2,0.44771525 2,1 L2,3.0142458 L12,3.0142458 L12,1 C12,0.44771525 12.4477153,-2.26485497e-13 13,-2.26485497e-13 C13.5522847,-2.26485497e-13 14,0.44771525 14,1 L14,3.0142458 C14,4.1188153 13.1045695,5.0142458 12,5.0142458 L2,5.0142458 C0.8954305,5.0142458 0,4.1188153 0,3.0142458 L0,1 Z M0,13.0142458 L0,11 C0,9.8954305 0.8954305,9 2,9 L12,9 C13.1045695,9 14,9.8954305 14,11 L14,13.0142458 C14,13.5665305 13.5522847,14.0142458 13,14.0142458 C12.4477153,14.0142458 12,13.5665305 12,13.0142458 L12,11 L2,11 L2,13.0142458 C2,13.5665305 1.55228475,14.0142458 1,14.0142458 C0.44771525,14.0142458 0,13.5665305 0,13.0142458 Z"></path></g></svg>',
159
+ shortcut: "Mod-Enter"
160
+ }
161
+ ],
162
+ commands: {
163
+ insertPageBreak: f
164
+ },
165
+ keymap: {
166
+ "Mod-Enter": "insertPageBreak"
167
+ }
168
+ });
169
+ export {
170
+ C as PageBreakPlugin
171
+ };
172
+ //# sourceMappingURL=PageBreakPlugin.native-DDjcDyRW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageBreakPlugin.native-DDjcDyRW.mjs","sources":["../../plugins/page-break/src/PageBreakPlugin.native.ts"],"sourcesContent":["import { Plugin } from '@editora/core';\n\n/**\n * Page Break Plugin - Native Implementation\n * \n * Features:\n * - Visual page break markers with dashed border\n * - Print integration (page-break-after: always)\n * - Block-level enforcement (no inline contexts)\n * - Click to select page break\n * - Keyboard navigation support\n * - Collapse adjacent page breaks\n * - Delete key removes page break\n * - Hover effects for better UX\n * - Accessibility compliant (ARIA labels, focus states)\n */\n\nlet pageBreakStyles: HTMLStyleElement | null = null;\n\nconst injectStyles = () => {\n if (pageBreakStyles) return;\n\n pageBreakStyles = document.createElement('style');\n pageBreakStyles.textContent = `\n .rte-page-break {\n display: block;\n position: relative;\n height: 12px;\n margin: 8px 0;\n background: linear-gradient(90deg, #ccc 0%, transparent 100%);\n border-top: 2px dashed #999;\n border-bottom: none;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n outline: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n }\n\n .rte-page-break::before {\n content: '⎙ PAGE BREAK';\n position: absolute;\n top: -12px;\n left: 0;\n font-size: 10px;\n font-weight: bold;\n color: #666;\n background: white;\n padding: 2px 6px;\n letter-spacing: 0.5px;\n opacity: 0.7;\n pointer-events: none;\n }\n\n .rte-page-break:hover {\n background: linear-gradient(90deg, #999 0%, transparent 100%);\n border-top-color: #666;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);\n }\n\n .rte-page-break:hover::before {\n opacity: 1;\n color: #333;\n }\n\n .rte-page-break:focus,\n .rte-page-break:focus-visible,\n .rte-page-break-selected {\n outline: 2px solid #0066cc;\n outline-offset: -2px;\n border-top-color: #0066cc;\n background: linear-gradient(90deg, #0066cc 0%, transparent 100%);\n }\n\n .rte-page-break * {\n user-select: none;\n }\n\n @media print {\n .rte-page-break {\n display: block;\n height: 0;\n margin: 0;\n background: none;\n border: none;\n page-break-after: always;\n }\n\n .rte-page-break::before {\n display: none;\n }\n }\n `;\n document.head.appendChild(pageBreakStyles);\n};\n\nconst isInlineContext = (node: Node): boolean => {\n const inlineElements = ['SPAN', 'A', 'STRONG', 'EM', 'B', 'I', 'U', 'SUP', 'SUB', 'CODE'];\n \n let current: HTMLElement | null = node.nodeType === Node.TEXT_NODE \n ? (node.parentElement as HTMLElement) \n : (node as HTMLElement);\n\n while (current && !current.hasAttribute('contenteditable')) {\n if (inlineElements.includes(current.tagName)) {\n return true;\n }\n current = current.parentElement;\n }\n\n return false;\n};\n\nconst getContainingBlock = (node: Node): HTMLElement | null => {\n const blockElements = ['DIV', 'P', 'BLOCKQUOTE', 'PRE', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'TD', 'TH'];\n let current: Node | null = node;\n\n while (current) {\n if (current.nodeType === Node.ELEMENT_NODE) {\n const element = current as HTMLElement;\n if (blockElements.includes(element.tagName)) {\n return element;\n }\n }\n current = current.parentNode;\n }\n\n return null;\n};\n\nconst collapseAdjacentPageBreaks = (pageBreak: HTMLElement) => {\n let next = pageBreak.nextElementSibling;\n \n while (next) {\n if (next.classList.contains('rte-page-break')) {\n next.remove();\n next = pageBreak.nextElementSibling;\n } else {\n break;\n }\n }\n\n let prev = pageBreak.previousElementSibling;\n while (prev) {\n if (prev.classList.contains('rte-page-break')) {\n const toRemove = prev;\n prev = prev.previousElementSibling;\n toRemove.remove();\n } else {\n break;\n }\n }\n};\n\nconst insertPageBreak = () => {\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return false;\n\n const range = selection.getRangeAt(0);\n const container = range.commonAncestorContainer as HTMLElement;\n\n // Check if we're in an inline context\n if (isInlineContext(container)) {\n console.warn('Page breaks cannot be inserted in inline contexts');\n return false;\n }\n\n // Get the block element containing the selection\n const blockElement = getContainingBlock(container);\n if (!blockElement) {\n console.warn('No block element found for page break insertion');\n return false;\n }\n\n // Create page break element\n const pageBreak = document.createElement('div');\n pageBreak.className = 'rte-page-break';\n pageBreak.setAttribute('data-page-break', 'true');\n pageBreak.setAttribute('data-type', 'page-break');\n pageBreak.setAttribute('contenteditable', 'false');\n pageBreak.setAttribute('tabindex', '0');\n pageBreak.setAttribute('role', 'separator');\n pageBreak.setAttribute('aria-label', 'Page break');\n\n // Handle click to select the page break\n pageBreak.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n pageBreak.focus();\n \n const newRange = document.createRange();\n newRange.selectNode(pageBreak);\n selection.removeAllRanges();\n selection.addRange(newRange);\n });\n\n // Handle keyboard navigation\n pageBreak.addEventListener('keydown', (e) => {\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault();\n const next = pageBreak.nextElementSibling || pageBreak.previousElementSibling;\n pageBreak.remove();\n \n if (next) {\n const newRange = document.createRange();\n newRange.selectNode(next);\n selection.removeAllRanges();\n selection.addRange(newRange);\n }\n } else if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {\n e.preventDefault();\n const next = pageBreak.nextElementSibling;\n if (next) {\n const newRange = document.createRange();\n newRange.setStart(next, 0);\n newRange.collapse(true);\n selection.removeAllRanges();\n selection.addRange(newRange);\n }\n } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {\n e.preventDefault();\n const prev = pageBreak.previousElementSibling;\n if (prev) {\n const newRange = document.createRange();\n newRange.selectNodeContents(prev);\n newRange.collapse(false);\n selection.removeAllRanges();\n selection.addRange(newRange);\n }\n }\n });\n\n // Insert after the block element\n blockElement.parentNode?.insertBefore(pageBreak, blockElement.nextSibling);\n\n // Collapse adjacent page breaks\n collapseAdjacentPageBreaks(pageBreak);\n\n // Move cursor after the page break\n const newRange = document.createRange();\n const nextNode = pageBreak.nextSibling;\n if (nextNode) {\n newRange.setStart(nextNode, 0);\n } else {\n // Create a new paragraph after the page break if nothing exists\n const p = document.createElement('p');\n p.innerHTML = '<br>';\n pageBreak.parentNode?.insertBefore(p, pageBreak.nextSibling);\n newRange.setStart(p, 0);\n }\n newRange.collapse(true);\n selection.removeAllRanges();\n selection.addRange(newRange);\n\n return true;\n};\n\nexport const PageBreakPlugin = (): Plugin => {\n // Inject styles on plugin initialization\n injectStyles();\n\n return {\n name: 'pageBreak',\n \n toolbar: [\n {\n label: 'Page Break',\n command: 'insertPageBreak',\n icon: '<svg fill=\"#000000\" width=\"24px\" height=\"24px\" viewBox=\"0 0 14 14\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"><path d=\"M1,6 L3,6 C3.55228475,6 4,6.44771525 4,7 C4,7.55228475 3.55228475,8 3,8 L1,8 C0.44771525,8 0,7.55228475 0,7 C0,6.44771525 0.44771525,6 1,6 Z M11,6 L13,6 C13.5522847,6 14,6.44771525 14,7 C14,7.55228475 13.5522847,8 13,8 L11,8 C10.4477153,8 10,7.55228475 10,7 C10,6.44771525 10.4477153,6 11,6 Z M6,6 L8,6 C8.55228475,6 9,6.44771525 9,7 C9,7.55228475 8.55228475,8 8,8 L6,8 C5.44771525,8 5,7.55228475 5,7 C5,6.44771525 5.44771525,6 6,6 Z M0,1 C0,0.44771525 0.44771525,-2.26485497e-13 1,-2.26485497e-13 C1.55228475,-2.26485497e-13 2,0.44771525 2,1 L2,3.0142458 L12,3.0142458 L12,1 C12,0.44771525 12.4477153,-2.26485497e-13 13,-2.26485497e-13 C13.5522847,-2.26485497e-13 14,0.44771525 14,1 L14,3.0142458 C14,4.1188153 13.1045695,5.0142458 12,5.0142458 L2,5.0142458 C0.8954305,5.0142458 0,4.1188153 0,3.0142458 L0,1 Z M0,13.0142458 L0,11 C0,9.8954305 0.8954305,9 2,9 L12,9 C13.1045695,9 14,9.8954305 14,11 L14,13.0142458 C14,13.5665305 13.5522847,14.0142458 13,14.0142458 C12.4477153,14.0142458 12,13.5665305 12,13.0142458 L12,11 L2,11 L2,13.0142458 C2,13.5665305 1.55228475,14.0142458 1,14.0142458 C0.44771525,14.0142458 0,13.5665305 0,13.0142458 Z\"></path></g></svg>',\n shortcut: 'Mod-Enter'\n }\n ],\n \n commands: {\n insertPageBreak\n },\n \n keymap: {\n 'Mod-Enter': 'insertPageBreak'\n }\n };\n};\n"],"names":["pageBreakStyles","injectStyles","isInlineContext","node","inlineElements","current","getContainingBlock","blockElements","element","collapseAdjacentPageBreaks","pageBreak","next","prev","toRemove","insertPageBreak","_a","_b","selection","container","blockElement","e","newRange","nextNode","p","PageBreakPlugin"],"mappings":"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"}