@aquera/nile-elements 2.0.16 → 2.0.18

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 (383) hide show
  1. package/README.md +6 -0
  2. package/dist/{index-f6944844.cjs.js → index-0c0c869d.cjs.js} +2 -2
  3. package/dist/{index-f6944844.cjs.js.map → index-0c0c869d.cjs.js.map} +1 -1
  4. package/dist/{index-403841c7.cjs.js → index-129ef6fb.cjs.js} +3 -3
  5. package/dist/{index-403841c7.cjs.js.map → index-129ef6fb.cjs.js.map} +1 -1
  6. package/dist/{index-1faa963c.esm.js → index-36f2a6b5.esm.js} +1 -1
  7. package/dist/index-4df50481.esm.js +1 -0
  8. package/dist/index-5d34cff1.esm.js +1 -0
  9. package/dist/index-7ae95edd.cjs.js +2 -0
  10. package/dist/{index-3ca67627.cjs.js.map → index-7ae95edd.cjs.js.map} +1 -1
  11. package/dist/index-7ca72b78.esm.js +1 -0
  12. package/dist/index-bbe23ad8.cjs.js +2 -0
  13. package/dist/index-bbe23ad8.cjs.js.map +1 -0
  14. package/dist/index-ccc6a799.cjs.js +5 -0
  15. package/dist/index-ccc6a799.cjs.js.map +1 -0
  16. package/dist/index.cjs.js +1 -1
  17. package/dist/index.esm.js +1 -1
  18. package/dist/index.js +686 -464
  19. package/dist/nile-auto-complete/index.cjs.js +1 -1
  20. package/dist/nile-auto-complete/nile-auto-complete.cjs.js +1 -1
  21. package/dist/nile-auto-complete/portal-manager.cjs.js +1 -1
  22. package/dist/nile-auto-complete/portal-utils.cjs.js +1 -1
  23. package/dist/nile-code-editor/extensionSetup.cjs.js +2 -2
  24. package/dist/nile-code-editor/index.cjs.js +1 -1
  25. package/dist/nile-code-editor/nile-code-editor.cjs.js +1 -1
  26. package/dist/nile-code-editor/theme.cjs.js +1 -1
  27. package/dist/nile-color-picker/index.cjs.js +1 -1
  28. package/dist/nile-color-picker/nile-color-picker.cjs.js +1 -1
  29. package/dist/nile-combobox/index.cjs.js +1 -1
  30. package/dist/nile-combobox/nile-combobox.cjs.js +1 -1
  31. package/dist/nile-combobox/portal-manager.cjs.js +1 -1
  32. package/dist/nile-context-menu/index.cjs.js +1 -1
  33. package/dist/nile-context-menu/nile-context-menu.cjs.js +1 -1
  34. package/dist/nile-context-submenu/index.cjs.js +1 -1
  35. package/dist/nile-context-submenu/nile-context-submenu.cjs.js +1 -1
  36. package/dist/nile-detail/index.cjs.js +1 -1
  37. package/dist/nile-detail/nile-detail.cjs.js +1 -1
  38. package/dist/nile-dropdown/index.cjs.js +1 -1
  39. package/dist/nile-dropdown/nile-dropdown.cjs.js +1 -1
  40. package/dist/nile-dropdown/portal-manager.cjs.js +1 -1
  41. package/dist/nile-file-upload/index.cjs.js +1 -1
  42. package/dist/nile-file-upload/nile-file-upload.cjs.js +1 -1
  43. package/dist/nile-file-upload/nile-file-upload.template.cjs.js +1 -1
  44. package/dist/nile-floating-panel/index.cjs.js +1 -1
  45. package/dist/nile-floating-panel/nile-floating-panel.cjs.js +1 -1
  46. package/dist/nile-lite-tooltip/index.cjs.js +1 -1
  47. package/dist/nile-lite-tooltip/nile-lite-tooltip.cjs.js +1 -1
  48. package/dist/nile-markdown-editor/index.cjs.js +1 -1
  49. package/dist/nile-markdown-editor/nile-markdown-editor.cjs.js +1 -1
  50. package/dist/nile-minimap/index.cjs.js +2 -0
  51. package/dist/nile-minimap/index.cjs.js.map +1 -0
  52. package/dist/nile-minimap/index.esm.js +1 -0
  53. package/dist/nile-minimap/nile-minimap.cjs.js +2 -0
  54. package/dist/nile-minimap/nile-minimap.cjs.js.map +1 -0
  55. package/dist/nile-minimap/nile-minimap.css.cjs.js +2 -0
  56. package/dist/nile-minimap/nile-minimap.css.cjs.js.map +1 -0
  57. package/dist/nile-minimap/nile-minimap.css.esm.js +150 -0
  58. package/dist/nile-minimap/nile-minimap.esm.js +22 -0
  59. package/dist/nile-popover/index.cjs.js +1 -1
  60. package/dist/nile-popover/nile-popover.cjs.js +1 -1
  61. package/dist/nile-popover/portal-manager.cjs.js +1 -1
  62. package/dist/nile-popup/index.cjs.js +1 -1
  63. package/dist/nile-popup/nile-popup.cjs.js +1 -1
  64. package/dist/nile-segmented-progress-bar/index.cjs.js +1 -1
  65. package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.cjs.js +1 -1
  66. package/dist/nile-select/index.cjs.js +1 -1
  67. package/dist/nile-select/nile-select.cjs.js +1 -1
  68. package/dist/nile-select/portal-manager.cjs.js +1 -1
  69. package/dist/nile-side-bar-action/index.cjs.js +1 -1
  70. package/dist/nile-side-bar-action/nile-side-bar-action.cjs.js +1 -1
  71. package/dist/nile-side-bar-action/portal-manager.cjs.js +1 -1
  72. package/dist/nile-tooltip/index.cjs.js +1 -1
  73. package/dist/nile-tooltip/nile-tooltip.cjs.js +1 -1
  74. package/dist/nile-virtual-select/index.cjs.js +1 -1
  75. package/dist/nile-virtual-select/nile-virtual-select.cjs.js +1 -1
  76. package/dist/nile-virtual-select/portal-manager.cjs.js +1 -1
  77. package/dist/nile-virtual-select/renderer.cjs.js +1 -1
  78. package/dist/nile-wysiwyg-editor/engine/commands.cjs.js +1 -1
  79. package/dist/nile-wysiwyg-editor/engine/commands.cjs.js.map +1 -1
  80. package/dist/nile-wysiwyg-editor/engine/commands.esm.js +1 -1
  81. package/dist/nile-wysiwyg-editor/engine/create-state.cjs.js +1 -1
  82. package/dist/nile-wysiwyg-editor/engine/create-state.cjs.js.map +1 -1
  83. package/dist/nile-wysiwyg-editor/engine/create-state.esm.js +1 -1
  84. package/dist/nile-wysiwyg-editor/engine/email-css.cjs.js +2 -0
  85. package/dist/nile-wysiwyg-editor/engine/email-css.cjs.js.map +1 -0
  86. package/dist/nile-wysiwyg-editor/engine/email-css.esm.js +1 -0
  87. package/dist/nile-wysiwyg-editor/engine/email-render.cjs.js +2 -0
  88. package/dist/nile-wysiwyg-editor/engine/email-render.cjs.js.map +1 -0
  89. package/dist/nile-wysiwyg-editor/engine/email-render.esm.js +1 -0
  90. package/dist/nile-wysiwyg-editor/engine/html-detect.cjs.js +2 -0
  91. package/dist/nile-wysiwyg-editor/engine/html-detect.cjs.js.map +1 -0
  92. package/dist/nile-wysiwyg-editor/engine/html-detect.esm.js +1 -0
  93. package/dist/nile-wysiwyg-editor/engine/index.cjs.js +1 -1
  94. package/dist/nile-wysiwyg-editor/engine/index.esm.js +1 -1
  95. package/dist/nile-wysiwyg-editor/engine/inputrules.cjs.js +1 -1
  96. package/dist/nile-wysiwyg-editor/engine/inputrules.cjs.js.map +1 -1
  97. package/dist/nile-wysiwyg-editor/engine/inputrules.esm.js +1 -1
  98. package/dist/nile-wysiwyg-editor/engine/keymap.cjs.js +1 -1
  99. package/dist/nile-wysiwyg-editor/engine/keymap.cjs.js.map +1 -1
  100. package/dist/nile-wysiwyg-editor/engine/keymap.esm.js +1 -1
  101. package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.cjs.js +1 -1
  102. package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.cjs.js.map +1 -1
  103. package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.esm.js +1 -1
  104. package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.cjs.js +1 -1
  105. package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.cjs.js.map +1 -1
  106. package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.esm.js +1 -1
  107. package/dist/nile-wysiwyg-editor/engine/plugins/embeds.cjs.js +1 -1
  108. package/dist/nile-wysiwyg-editor/engine/plugins/embeds.cjs.js.map +1 -1
  109. package/dist/nile-wysiwyg-editor/engine/plugins/embeds.esm.js +1 -1
  110. package/dist/nile-wysiwyg-editor/engine/plugins/find-replace.cjs.js +1 -1
  111. package/dist/nile-wysiwyg-editor/engine/plugins/find-replace.cjs.js.map +1 -1
  112. package/dist/nile-wysiwyg-editor/engine/plugins/find-replace.esm.js +1 -1
  113. package/dist/nile-wysiwyg-editor/engine/plugins/format-painter.cjs.js +1 -1
  114. package/dist/nile-wysiwyg-editor/engine/plugins/format-painter.cjs.js.map +1 -1
  115. package/dist/nile-wysiwyg-editor/engine/plugins/format-painter.esm.js +1 -1
  116. package/dist/nile-wysiwyg-editor/engine/plugins/image-view.cjs.js +1 -1
  117. package/dist/nile-wysiwyg-editor/engine/plugins/image-view.cjs.js.map +1 -1
  118. package/dist/nile-wysiwyg-editor/engine/plugins/image-view.esm.js +1 -1
  119. package/dist/nile-wysiwyg-editor/engine/plugins/image.cjs.js +1 -1
  120. package/dist/nile-wysiwyg-editor/engine/plugins/image.cjs.js.map +1 -1
  121. package/dist/nile-wysiwyg-editor/engine/plugins/image.esm.js +1 -1
  122. package/dist/nile-wysiwyg-editor/engine/plugins/link.cjs.js +1 -1
  123. package/dist/nile-wysiwyg-editor/engine/plugins/link.cjs.js.map +1 -1
  124. package/dist/nile-wysiwyg-editor/engine/plugins/link.esm.js +1 -1
  125. package/dist/nile-wysiwyg-editor/engine/plugins/max-length.cjs.js +1 -1
  126. package/dist/nile-wysiwyg-editor/engine/plugins/max-length.cjs.js.map +1 -1
  127. package/dist/nile-wysiwyg-editor/engine/plugins/max-length.esm.js +1 -1
  128. package/dist/nile-wysiwyg-editor/engine/plugins/paste.cjs.js +1 -1
  129. package/dist/nile-wysiwyg-editor/engine/plugins/paste.cjs.js.map +1 -1
  130. package/dist/nile-wysiwyg-editor/engine/plugins/paste.esm.js +1 -1
  131. package/dist/nile-wysiwyg-editor/engine/plugins/placeholder.cjs.js +1 -1
  132. package/dist/nile-wysiwyg-editor/engine/plugins/placeholder.cjs.js.map +1 -1
  133. package/dist/nile-wysiwyg-editor/engine/plugins/placeholder.esm.js +1 -1
  134. package/dist/nile-wysiwyg-editor/engine/plugins/single-line.cjs.js +1 -1
  135. package/dist/nile-wysiwyg-editor/engine/plugins/single-line.cjs.js.map +1 -1
  136. package/dist/nile-wysiwyg-editor/engine/plugins/single-line.esm.js +1 -1
  137. package/dist/nile-wysiwyg-editor/engine/plugins/suggestions.cjs.js +1 -1
  138. package/dist/nile-wysiwyg-editor/engine/plugins/suggestions.cjs.js.map +1 -1
  139. package/dist/nile-wysiwyg-editor/engine/plugins/suggestions.esm.js +1 -1
  140. package/dist/nile-wysiwyg-editor/engine/plugins/tables.cjs.js +1 -1
  141. package/dist/nile-wysiwyg-editor/engine/plugins/tables.cjs.js.map +1 -1
  142. package/dist/nile-wysiwyg-editor/engine/plugins/tables.esm.js +1 -1
  143. package/dist/nile-wysiwyg-editor/engine/sanitize.cjs.js +2 -1
  144. package/dist/nile-wysiwyg-editor/engine/sanitize.cjs.js.map +1 -1
  145. package/dist/nile-wysiwyg-editor/engine/sanitize.esm.js +1 -1
  146. package/dist/nile-wysiwyg-editor/engine/schema.cjs.js +1 -1
  147. package/dist/nile-wysiwyg-editor/engine/schema.cjs.js.map +1 -1
  148. package/dist/nile-wysiwyg-editor/engine/schema.esm.js +1 -1
  149. package/dist/nile-wysiwyg-editor/engine/selection-state.cjs.js +1 -1
  150. package/dist/nile-wysiwyg-editor/engine/selection-state.cjs.js.map +1 -1
  151. package/dist/nile-wysiwyg-editor/engine/selection-state.esm.js +1 -1
  152. package/dist/nile-wysiwyg-editor/engine/serializer.cjs.js +1 -1
  153. package/dist/nile-wysiwyg-editor/engine/serializer.cjs.js.map +1 -1
  154. package/dist/nile-wysiwyg-editor/engine/serializer.esm.js +1 -1
  155. package/dist/nile-wysiwyg-editor/index.cjs.js +1 -1
  156. package/dist/nile-wysiwyg-editor/index.esm.js +1 -1
  157. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js +1 -1
  158. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js.map +1 -1
  159. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.cjs.js +1 -1
  160. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.cjs.js.map +1 -1
  161. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.esm.js +45 -4
  162. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.esm.js +2 -2
  163. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.cjs.js +1 -1
  164. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.cjs.js +1 -1
  165. package/dist/nile-wysiwyg-editor/ui/bookmark-panel.cjs.js +1 -1
  166. package/dist/nile-wysiwyg-editor/ui/bookmark-panel.cjs.js.map +1 -1
  167. package/dist/nile-wysiwyg-editor/ui/bookmark-panel.esm.js +2 -2
  168. package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js +1 -1
  169. package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js.map +1 -1
  170. package/dist/nile-wysiwyg-editor/ui/bubble-menu.esm.js +5 -5
  171. package/dist/nile-wysiwyg-editor/ui/code-block-menu.cjs.js +1 -1
  172. package/dist/nile-wysiwyg-editor/ui/code-block-menu.cjs.js.map +1 -1
  173. package/dist/nile-wysiwyg-editor/ui/code-block-menu.esm.js +1 -1
  174. package/dist/nile-wysiwyg-editor/ui/embed-menu.cjs.js +1 -1
  175. package/dist/nile-wysiwyg-editor/ui/embed-menu.cjs.js.map +1 -1
  176. package/dist/nile-wysiwyg-editor/ui/embed-menu.esm.js +1 -1
  177. package/dist/nile-wysiwyg-editor/ui/embed-panel.cjs.js +1 -1
  178. package/dist/nile-wysiwyg-editor/ui/embed-panel.cjs.js.map +1 -1
  179. package/dist/nile-wysiwyg-editor/ui/embed-panel.esm.js +2 -2
  180. package/dist/nile-wysiwyg-editor/ui/emoji-picker.cjs.js +1 -1
  181. package/dist/nile-wysiwyg-editor/ui/emoji-picker.cjs.js.map +1 -1
  182. package/dist/nile-wysiwyg-editor/ui/emoji-picker.esm.js +1 -1
  183. package/dist/nile-wysiwyg-editor/ui/find-replace.cjs.js +1 -1
  184. package/dist/nile-wysiwyg-editor/ui/find-replace.cjs.js.map +1 -1
  185. package/dist/nile-wysiwyg-editor/ui/find-replace.esm.js +3 -3
  186. package/dist/nile-wysiwyg-editor/ui/image-menu.cjs.js +1 -1
  187. package/dist/nile-wysiwyg-editor/ui/image-menu.cjs.js.map +1 -1
  188. package/dist/nile-wysiwyg-editor/ui/image-menu.esm.js +3 -3
  189. package/dist/nile-wysiwyg-editor/ui/image-panel.cjs.js +1 -1
  190. package/dist/nile-wysiwyg-editor/ui/image-panel.cjs.js.map +1 -1
  191. package/dist/nile-wysiwyg-editor/ui/image-panel.esm.js +1 -1
  192. package/dist/nile-wysiwyg-editor/ui/insert-menu.cjs.js +1 -1
  193. package/dist/nile-wysiwyg-editor/ui/insert-menu.cjs.js.map +1 -1
  194. package/dist/nile-wysiwyg-editor/ui/insert-menu.esm.js +1 -1
  195. package/dist/nile-wysiwyg-editor/ui/link-editor.cjs.js +1 -1
  196. package/dist/nile-wysiwyg-editor/ui/link-editor.cjs.js.map +1 -1
  197. package/dist/nile-wysiwyg-editor/ui/link-editor.esm.js +9 -9
  198. package/dist/nile-wysiwyg-editor/ui/markdown-panel.cjs.js +1 -1
  199. package/dist/nile-wysiwyg-editor/ui/markdown-panel.cjs.js.map +1 -1
  200. package/dist/nile-wysiwyg-editor/ui/markdown-panel.esm.js +1 -1
  201. package/dist/nile-wysiwyg-editor/ui/math-panel.cjs.js +1 -1
  202. package/dist/nile-wysiwyg-editor/ui/math-panel.cjs.js.map +1 -1
  203. package/dist/nile-wysiwyg-editor/ui/math-panel.esm.js +1 -1
  204. package/dist/nile-wysiwyg-editor/ui/shortcut-help.cjs.js +1 -1
  205. package/dist/nile-wysiwyg-editor/ui/shortcut-help.cjs.js.map +1 -1
  206. package/dist/nile-wysiwyg-editor/ui/shortcut-help.esm.js +1 -1
  207. package/dist/nile-wysiwyg-editor/ui/source-view.cjs.js +1 -1
  208. package/dist/nile-wysiwyg-editor/ui/source-view.cjs.js.map +1 -1
  209. package/dist/nile-wysiwyg-editor/ui/source-view.esm.js +4 -4
  210. package/dist/nile-wysiwyg-editor/ui/special-chars.cjs.js +1 -1
  211. package/dist/nile-wysiwyg-editor/ui/special-chars.cjs.js.map +1 -1
  212. package/dist/nile-wysiwyg-editor/ui/special-chars.esm.js +1 -1
  213. package/dist/nile-wysiwyg-editor/ui/suggest-list.cjs.js +1 -1
  214. package/dist/nile-wysiwyg-editor/ui/suggest-list.cjs.js.map +1 -1
  215. package/dist/nile-wysiwyg-editor/ui/suggest-list.esm.js +23 -12
  216. package/dist/nile-wysiwyg-editor/ui/table-grid-picker.cjs.js +1 -1
  217. package/dist/nile-wysiwyg-editor/ui/table-grid-picker.cjs.js.map +1 -1
  218. package/dist/nile-wysiwyg-editor/ui/table-grid-picker.esm.js +7 -7
  219. package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js +1 -1
  220. package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js.map +1 -1
  221. package/dist/nile-wysiwyg-editor/ui/table-menu.esm.js +1 -1
  222. package/dist/src/index.d.ts +1 -0
  223. package/dist/src/index.js +1 -0
  224. package/dist/src/index.js.map +1 -1
  225. package/dist/src/nile-minimap/index.d.ts +1 -0
  226. package/dist/src/nile-minimap/index.js +2 -0
  227. package/dist/src/nile-minimap/index.js.map +1 -0
  228. package/dist/src/nile-minimap/nile-minimap.css.d.ts +12 -0
  229. package/dist/src/nile-minimap/nile-minimap.css.js +162 -0
  230. package/dist/src/nile-minimap/nile-minimap.css.js.map +1 -0
  231. package/dist/src/nile-minimap/nile-minimap.d.ts +131 -0
  232. package/dist/src/nile-minimap/nile-minimap.js +704 -0
  233. package/dist/src/nile-minimap/nile-minimap.js.map +1 -0
  234. package/dist/src/nile-minimap/nile-minimap.test.d.ts +1 -0
  235. package/dist/src/nile-minimap/nile-minimap.test.js +785 -0
  236. package/dist/src/nile-minimap/nile-minimap.test.js.map +1 -0
  237. package/dist/src/nile-wysiwyg-editor/engine/create-state.d.ts +5 -0
  238. package/dist/src/nile-wysiwyg-editor/engine/create-state.js +2 -0
  239. package/dist/src/nile-wysiwyg-editor/engine/create-state.js.map +1 -1
  240. package/dist/src/nile-wysiwyg-editor/engine/email-css.d.ts +14 -0
  241. package/dist/src/nile-wysiwyg-editor/engine/email-css.js +140 -0
  242. package/dist/src/nile-wysiwyg-editor/engine/email-css.js.map +1 -0
  243. package/dist/src/nile-wysiwyg-editor/engine/email-fidelity.test.d.ts +1 -0
  244. package/dist/src/nile-wysiwyg-editor/engine/email-fidelity.test.js +1045 -0
  245. package/dist/src/nile-wysiwyg-editor/engine/email-fidelity.test.js.map +1 -0
  246. package/dist/src/nile-wysiwyg-editor/engine/email-render.d.ts +11 -0
  247. package/dist/src/nile-wysiwyg-editor/engine/email-render.js +93 -0
  248. package/dist/src/nile-wysiwyg-editor/engine/email-render.js.map +1 -0
  249. package/dist/src/nile-wysiwyg-editor/engine/html-detect.d.ts +2 -0
  250. package/dist/src/nile-wysiwyg-editor/engine/html-detect.js +24 -0
  251. package/dist/src/nile-wysiwyg-editor/engine/html-detect.js.map +1 -0
  252. package/dist/src/nile-wysiwyg-editor/engine/index.d.ts +4 -1
  253. package/dist/src/nile-wysiwyg-editor/engine/index.js +3 -1
  254. package/dist/src/nile-wysiwyg-editor/engine/index.js.map +1 -1
  255. package/dist/src/nile-wysiwyg-editor/engine/inputrules.d.ts +0 -5
  256. package/dist/src/nile-wysiwyg-editor/engine/inputrules.js +19 -0
  257. package/dist/src/nile-wysiwyg-editor/engine/inputrules.js.map +1 -1
  258. package/dist/src/nile-wysiwyg-editor/engine/plugins/image-view.js +3 -2
  259. package/dist/src/nile-wysiwyg-editor/engine/plugins/image-view.js.map +1 -1
  260. package/dist/src/nile-wysiwyg-editor/engine/plugins/link.d.ts +4 -0
  261. package/dist/src/nile-wysiwyg-editor/engine/plugins/link.js +56 -1
  262. package/dist/src/nile-wysiwyg-editor/engine/plugins/link.js.map +1 -1
  263. package/dist/src/nile-wysiwyg-editor/engine/plugins/paste.d.ts +5 -0
  264. package/dist/src/nile-wysiwyg-editor/engine/plugins/paste.js +27 -6
  265. package/dist/src/nile-wysiwyg-editor/engine/plugins/paste.js.map +1 -1
  266. package/dist/src/nile-wysiwyg-editor/engine/plugins/tables.js +30 -7
  267. package/dist/src/nile-wysiwyg-editor/engine/plugins/tables.js.map +1 -1
  268. package/dist/src/nile-wysiwyg-editor/engine/pm.test.js +46 -0
  269. package/dist/src/nile-wysiwyg-editor/engine/pm.test.js.map +1 -1
  270. package/dist/src/nile-wysiwyg-editor/engine/sanitize.d.ts +9 -1
  271. package/dist/src/nile-wysiwyg-editor/engine/sanitize.js +730 -7
  272. package/dist/src/nile-wysiwyg-editor/engine/sanitize.js.map +1 -1
  273. package/dist/src/nile-wysiwyg-editor/engine/schema.d.ts +3 -0
  274. package/dist/src/nile-wysiwyg-editor/engine/schema.js +215 -34
  275. package/dist/src/nile-wysiwyg-editor/engine/schema.js.map +1 -1
  276. package/dist/src/nile-wysiwyg-editor/engine/selection-state.js +3 -1
  277. package/dist/src/nile-wysiwyg-editor/engine/selection-state.js.map +1 -1
  278. package/dist/src/nile-wysiwyg-editor/engine/serializer.d.ts +12 -4
  279. package/dist/src/nile-wysiwyg-editor/engine/serializer.js +18 -8
  280. package/dist/src/nile-wysiwyg-editor/engine/serializer.js.map +1 -1
  281. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.d.ts +1 -0
  282. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.js +287 -0
  283. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.js.map +1 -0
  284. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.js +45 -4
  285. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.js.map +1 -1
  286. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.d.ts +23 -0
  287. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.js +113 -15
  288. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.js.map +1 -1
  289. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.js +213 -0
  290. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.js.map +1 -1
  291. package/dist/src/nile-wysiwyg-editor/ui/bookmark-panel.js +2 -2
  292. package/dist/src/nile-wysiwyg-editor/ui/bookmark-panel.js.map +1 -1
  293. package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.js +1 -1
  294. package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.js.map +1 -1
  295. package/dist/src/nile-wysiwyg-editor/ui/embed-menu.js +1 -1
  296. package/dist/src/nile-wysiwyg-editor/ui/embed-menu.js.map +1 -1
  297. package/dist/src/nile-wysiwyg-editor/ui/embed-panel.js +1 -1
  298. package/dist/src/nile-wysiwyg-editor/ui/embed-panel.js.map +1 -1
  299. package/dist/src/nile-wysiwyg-editor/ui/emoji-picker.js +1 -1
  300. package/dist/src/nile-wysiwyg-editor/ui/emoji-picker.js.map +1 -1
  301. package/dist/src/nile-wysiwyg-editor/ui/find-replace.js +1 -1
  302. package/dist/src/nile-wysiwyg-editor/ui/find-replace.js.map +1 -1
  303. package/dist/src/nile-wysiwyg-editor/ui/image-menu.js +1 -1
  304. package/dist/src/nile-wysiwyg-editor/ui/image-menu.js.map +1 -1
  305. package/dist/src/nile-wysiwyg-editor/ui/image-panel.js +1 -1
  306. package/dist/src/nile-wysiwyg-editor/ui/image-panel.js.map +1 -1
  307. package/dist/src/nile-wysiwyg-editor/ui/insert-menu.js +1 -1
  308. package/dist/src/nile-wysiwyg-editor/ui/insert-menu.js.map +1 -1
  309. package/dist/src/nile-wysiwyg-editor/ui/link-editor.js +2 -2
  310. package/dist/src/nile-wysiwyg-editor/ui/link-editor.js.map +1 -1
  311. package/dist/src/nile-wysiwyg-editor/ui/markdown-panel.js +1 -1
  312. package/dist/src/nile-wysiwyg-editor/ui/markdown-panel.js.map +1 -1
  313. package/dist/src/nile-wysiwyg-editor/ui/math-panel.js +1 -1
  314. package/dist/src/nile-wysiwyg-editor/ui/math-panel.js.map +1 -1
  315. package/dist/src/nile-wysiwyg-editor/ui/shortcut-help.js +1 -1
  316. package/dist/src/nile-wysiwyg-editor/ui/shortcut-help.js.map +1 -1
  317. package/dist/src/nile-wysiwyg-editor/ui/source-view.js +2 -2
  318. package/dist/src/nile-wysiwyg-editor/ui/source-view.js.map +1 -1
  319. package/dist/src/nile-wysiwyg-editor/ui/special-chars.js +1 -1
  320. package/dist/src/nile-wysiwyg-editor/ui/special-chars.js.map +1 -1
  321. package/dist/src/nile-wysiwyg-editor/ui/suggest-list.js +14 -3
  322. package/dist/src/nile-wysiwyg-editor/ui/suggest-list.js.map +1 -1
  323. package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.js +2 -2
  324. package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.js.map +1 -1
  325. package/dist/src/nile-wysiwyg-editor/ui/table-menu.js +1 -1
  326. package/dist/src/nile-wysiwyg-editor/ui/table-menu.js.map +1 -1
  327. package/dist/src/version.js +1 -1
  328. package/dist/src/version.js.map +1 -1
  329. package/dist/tsconfig.tsbuildinfo +1 -1
  330. package/package.json +2 -1
  331. package/src/index.ts +1 -0
  332. package/src/nile-minimap/index.ts +1 -0
  333. package/src/nile-minimap/nile-minimap.css.ts +164 -0
  334. package/src/nile-minimap/nile-minimap.test.ts +924 -0
  335. package/src/nile-minimap/nile-minimap.ts +796 -0
  336. package/src/nile-wysiwyg-editor/engine/create-state.ts +7 -0
  337. package/src/nile-wysiwyg-editor/engine/email-css.ts +136 -0
  338. package/src/nile-wysiwyg-editor/engine/email-fidelity.test.ts +1347 -0
  339. package/src/nile-wysiwyg-editor/engine/email-render.ts +99 -0
  340. package/src/nile-wysiwyg-editor/engine/html-detect.ts +26 -0
  341. package/src/nile-wysiwyg-editor/engine/index.ts +10 -1
  342. package/src/nile-wysiwyg-editor/engine/inputrules.ts +18 -1
  343. package/src/nile-wysiwyg-editor/engine/plugins/image-view.ts +3 -2
  344. package/src/nile-wysiwyg-editor/engine/plugins/link.ts +58 -2
  345. package/src/nile-wysiwyg-editor/engine/plugins/paste.ts +31 -8
  346. package/src/nile-wysiwyg-editor/engine/plugins/tables.ts +29 -7
  347. package/src/nile-wysiwyg-editor/engine/pm.test.ts +73 -0
  348. package/src/nile-wysiwyg-editor/engine/sanitize.ts +729 -7
  349. package/src/nile-wysiwyg-editor/engine/schema.ts +206 -33
  350. package/src/nile-wysiwyg-editor/engine/selection-state.ts +3 -1
  351. package/src/nile-wysiwyg-editor/engine/serializer.ts +30 -8
  352. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.ts +357 -0
  353. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.ts +45 -4
  354. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.ts +258 -0
  355. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.ts +119 -12
  356. package/src/nile-wysiwyg-editor/ui/bookmark-panel.ts +2 -2
  357. package/src/nile-wysiwyg-editor/ui/bubble-menu.ts +1 -1
  358. package/src/nile-wysiwyg-editor/ui/embed-menu.ts +1 -1
  359. package/src/nile-wysiwyg-editor/ui/embed-panel.ts +1 -1
  360. package/src/nile-wysiwyg-editor/ui/emoji-picker.ts +1 -1
  361. package/src/nile-wysiwyg-editor/ui/find-replace.ts +1 -1
  362. package/src/nile-wysiwyg-editor/ui/image-menu.ts +1 -1
  363. package/src/nile-wysiwyg-editor/ui/image-panel.ts +1 -1
  364. package/src/nile-wysiwyg-editor/ui/insert-menu.ts +1 -1
  365. package/src/nile-wysiwyg-editor/ui/link-editor.ts +2 -2
  366. package/src/nile-wysiwyg-editor/ui/markdown-panel.ts +1 -1
  367. package/src/nile-wysiwyg-editor/ui/math-panel.ts +1 -1
  368. package/src/nile-wysiwyg-editor/ui/shortcut-help.ts +1 -1
  369. package/src/nile-wysiwyg-editor/ui/source-view.ts +2 -2
  370. package/src/nile-wysiwyg-editor/ui/special-chars.ts +1 -1
  371. package/src/nile-wysiwyg-editor/ui/suggest-list.ts +14 -3
  372. package/src/nile-wysiwyg-editor/ui/table-grid-picker.ts +2 -2
  373. package/src/nile-wysiwyg-editor/ui/table-menu.ts +1 -1
  374. package/vscode-html-custom-data.json +116 -25
  375. package/web-test-runner.config.mjs +4 -0
  376. package/dist/index-3ca67627.cjs.js +0 -2
  377. package/dist/index-6f3fa4ab.esm.js +0 -1
  378. package/dist/index-7b1c9857.esm.js +0 -1
  379. package/dist/index-89c520e9.cjs.js +0 -5
  380. package/dist/index-89c520e9.cjs.js.map +0 -1
  381. package/dist/index-ba47645d.esm.js +0 -1
  382. package/dist/index-c3210a9c.cjs.js +0 -2
  383. package/dist/index-c3210a9c.cjs.js.map +0 -1
@@ -3,11 +3,16 @@ import { addListNodes } from 'prosemirror-schema-list';
3
3
  import { tableNodes } from 'prosemirror-tables';
4
4
  import OrderedMap from 'orderedmap';
5
5
  import { EMBED_SANDBOX, EMBED_REFERRER_POLICY } from './plugins/embeds';
6
+ import { sanitizeExtraStyleForWrite } from './email-css';
7
+ import { sanitizeTableTextStyleForWrite } from './sanitize';
6
8
 
7
9
  export type Alignment = 'left' | 'center' | 'right' | 'justify';
8
10
 
9
11
  const ALIGN_VALUES: Alignment[] = ['left', 'center', 'right', 'justify'];
10
12
 
13
+ /** Keywords a cell's `text-align` attr may hold (email-fidelity). */
14
+ const CELL_ALIGN_KEYWORDS = new Set(['left', 'center', 'right', 'justify', 'start', 'end']);
15
+
11
16
  function getAlignFromDom(dom: HTMLElement): Alignment | null {
12
17
  const value = dom.style.textAlign || dom.getAttribute('align') || '';
13
18
  return (ALIGN_VALUES as string[]).includes(value) ? (value as Alignment) : null;
@@ -17,6 +22,40 @@ function alignStyle(align: Alignment | null): string | null {
17
22
  return align ? `text-align: ${align}` : null;
18
23
  }
19
24
 
25
+ /** Image/figure width: a number is px, a `<n>%` string a percentage. */
26
+ const IMAGE_PERCENT = /^(\d{1,3}(?:\.\d{1,2})?)%$/;
27
+
28
+ export function imageWidthCss(width: number | string | null): string | null {
29
+ if (typeof width === 'number') return width > 0 ? `${width}px` : null;
30
+ if (typeof width === 'string') {
31
+ const match = IMAGE_PERCENT.exec(width.trim());
32
+ if (match) {
33
+ const n = parseFloat(match[1]);
34
+ if (n > 0 && n <= 100) return width.trim();
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+
40
+ /** Reads an img/figure width: a valid `<n>%` keeps the string, else px rounds. */
41
+ function imageWidthFromDom(styleWidth: string, attrWidth?: string): number | string | null {
42
+ const trimmed = styleWidth.trim();
43
+ // A percentage style width is kept only in range; an out-of-range/invalid one
44
+ // (e.g. '150%') is dropped rather than silently reinterpreted as px.
45
+ if (trimmed.endsWith('%')) {
46
+ const match = IMAGE_PERCENT.exec(trimmed);
47
+ if (match) {
48
+ const n = parseFloat(match[1]);
49
+ if (n > 0 && n <= 100) return trimmed;
50
+ }
51
+ return null;
52
+ }
53
+ const sw = parseFloat(styleWidth);
54
+ const aw = parseFloat(attrWidth ?? '');
55
+ const px = Number.isFinite(sw) ? Math.round(sw) : Number.isFinite(aw) ? Math.round(aw) : null;
56
+ return px && px > 0 ? px : null;
57
+ }
58
+
20
59
  /** Indent depth in 40px steps, like CKEditor/Google Docs. */
21
60
  export const INDENT_STEP_PX = 40;
22
61
  export const MAX_INDENT = 8;
@@ -41,17 +80,36 @@ function getLineHeightFromDom(dom: HTMLElement): string | null {
41
80
  return raw;
42
81
  }
43
82
 
44
- /** Combined style string for align + indent + line-height textblock attrs. */
83
+ /** Fidelity block margin, stored as a ready-to-emit declaration string. */
84
+ function getMarginFromDom(dom: HTMLElement): string | null {
85
+ const s = dom.style;
86
+ if (s.margin) return `margin: ${s.margin}`;
87
+ const parts: string[] = [];
88
+ if (s.marginTop) parts.push(`margin-top: ${s.marginTop}`);
89
+ if (s.marginBottom) parts.push(`margin-bottom: ${s.marginBottom}`);
90
+ return parts.length ? parts.join('; ') : null;
91
+ }
92
+
93
+ /** Combined style string for margin + align + indent + line-height textblock attrs. */
45
94
  function blockStyle(attrs: {
46
95
  align?: Alignment | null;
47
96
  indent?: number;
48
97
  lineHeight?: string | null;
98
+ margin?: string | null;
99
+ extraStyle?: string | null;
49
100
  }): string | null {
50
101
  const parts: string[] = [];
102
+ if (attrs.margin) parts.push(attrs.margin);
51
103
  const align = alignStyle(attrs.align ?? null);
52
104
  if (align) parts.push(align);
53
105
  if (attrs.indent) parts.push(`margin-inline-start: ${attrs.indent * INDENT_STEP_PX}px`);
54
106
  if (attrs.lineHeight) parts.push(`line-height: ${attrs.lineHeight}`);
107
+ // Per-app extension declarations, re-validated against the permanent denylist
108
+ // + value grammar (the singleton schema can't see the per-app allowlist).
109
+ if (attrs.extraStyle) {
110
+ const safe = sanitizeExtraStyleForWrite(attrs.extraStyle);
111
+ if (safe) parts.push(safe);
112
+ }
55
113
  return parts.length ? parts.join('; ') : null;
56
114
  }
57
115
 
@@ -165,6 +223,8 @@ const nodes: Record<string, NodeSpec> = {
165
223
  align: { default: null },
166
224
  indent: { default: 0 },
167
225
  lineHeight: { default: null },
226
+ margin: { default: null },
227
+ extraStyle: { default: null },
168
228
  },
169
229
  parseDOM: [
170
230
  {
@@ -173,6 +233,8 @@ const nodes: Record<string, NodeSpec> = {
173
233
  align: getAlignFromDom(dom),
174
234
  indent: getIndentFromDom(dom),
175
235
  lineHeight: getLineHeightFromDom(dom),
236
+ margin: getMarginFromDom(dom),
237
+ extraStyle: dom.getAttribute('data-extra-style'),
176
238
  }),
177
239
  },
178
240
  ],
@@ -191,6 +253,8 @@ const nodes: Record<string, NodeSpec> = {
191
253
  align: { default: null },
192
254
  indent: { default: 0 },
193
255
  lineHeight: { default: null },
256
+ margin: { default: null },
257
+ extraStyle: { default: null },
194
258
  },
195
259
  parseDOM: [1, 2, 3, 4, 5, 6].map(level => ({
196
260
  tag: `h${level}`,
@@ -199,6 +263,8 @@ const nodes: Record<string, NodeSpec> = {
199
263
  align: getAlignFromDom(dom),
200
264
  indent: getIndentFromDom(dom),
201
265
  lineHeight: getLineHeightFromDom(dom),
266
+ margin: getMarginFromDom(dom),
267
+ extraStyle: dom.getAttribute('data-extra-style'),
202
268
  }),
203
269
  })),
204
270
  toDOM(node) {
@@ -262,10 +328,7 @@ const nodes: Record<string, NodeSpec> = {
262
328
  },
263
329
  },
264
330
 
265
- /**
266
- * ProseMirror's canonical inline image, extended with a `width` attr (px)
267
- * written by the drag-resize handles.
268
- */
331
+ /** Inline image with a `width` attr (px number or `<n>%`). */
269
332
  image: {
270
333
  inline: true,
271
334
  group: 'inline',
@@ -279,21 +342,12 @@ const nodes: Record<string, NodeSpec> = {
279
342
  parseDOM: [
280
343
  {
281
344
  tag: 'img[src]',
282
- getAttrs: (dom: HTMLElement) => {
283
- const styleWidth = parseFloat(dom.style.width);
284
- const attrWidth = parseFloat(dom.getAttribute('width') ?? '');
285
- const width = Number.isFinite(styleWidth)
286
- ? Math.round(styleWidth)
287
- : Number.isFinite(attrWidth)
288
- ? Math.round(attrWidth)
289
- : null;
290
- return {
291
- src: dom.getAttribute('src'),
292
- alt: dom.getAttribute('alt'),
293
- title: dom.getAttribute('title'),
294
- width: width && width > 0 ? width : null,
295
- };
296
- },
345
+ getAttrs: (dom: HTMLElement) => ({
346
+ src: dom.getAttribute('src'),
347
+ alt: dom.getAttribute('alt'),
348
+ title: dom.getAttribute('title'),
349
+ width: imageWidthFromDom(dom.style.width, dom.getAttribute('width') ?? ''),
350
+ }),
297
351
  },
298
352
  ],
299
353
  toDOM(node) {
@@ -301,7 +355,8 @@ const nodes: Record<string, NodeSpec> = {
301
355
  const attrs: Record<string, string> = { src };
302
356
  if (alt) attrs.alt = alt;
303
357
  if (title) attrs.title = title;
304
- if (width) attrs.style = `width: ${width}px`;
358
+ const css = imageWidthCss(width);
359
+ if (css) attrs.style = `width: ${css}`;
305
360
  return ['img', attrs];
306
361
  },
307
362
  },
@@ -331,16 +386,12 @@ const nodes: Record<string, NodeSpec> = {
331
386
  getAttrs: (dom: HTMLElement) => {
332
387
  const img = dom.querySelector('img[src]') as HTMLElement | null;
333
388
  if (!img) return false;
334
- const styleWidth = parseFloat(img.style.width || dom.style.width);
335
389
  const align = dom.getAttribute('data-align');
336
390
  return {
337
391
  src: img.getAttribute('src'),
338
392
  alt: img.getAttribute('alt'),
339
393
  title: img.getAttribute('title'),
340
- width:
341
- Number.isFinite(styleWidth) && styleWidth > 0
342
- ? Math.round(styleWidth)
343
- : null,
394
+ width: imageWidthFromDom(img.style.width || dom.style.width),
344
395
  align: align === 'left' || align === 'center' || align === 'right' ? align : null,
345
396
  };
346
397
  },
@@ -351,7 +402,8 @@ const nodes: Record<string, NodeSpec> = {
351
402
  const figureAttrs: Record<string, string> = { class: 'nile-wysiwyg__figure' };
352
403
  if (align) figureAttrs['data-align'] = align;
353
404
  const styles: string[] = [];
354
- if (width) styles.push(`width: ${width}px`);
405
+ const widthCss = imageWidthCss(width);
406
+ if (widthCss) styles.push(`width: ${widthCss}`);
355
407
  if (align === 'center') styles.push('margin-left: auto; margin-right: auto');
356
408
  else if (align === 'right') styles.push('margin-left: auto; margin-right: 0');
357
409
  if (styles.length) figureAttrs.style = styles.join('; ');
@@ -657,7 +709,20 @@ const nodes: Record<string, NodeSpec> = {
657
709
  },
658
710
  };
659
711
 
660
- /** Table nodes from prosemirror-tables, with cell background support. */
712
+ /** A cell attr that reads and writes one inline-style declaration. */
713
+ function cellStyleAttr(cssName: string) {
714
+ return {
715
+ default: null,
716
+ getFromDOM(dom: HTMLElement) {
717
+ return dom.style.getPropertyValue(cssName) || null;
718
+ },
719
+ setDOMAttr(value: unknown, attrs: Record<string, unknown>) {
720
+ if (value) attrs.style = `${(attrs.style as string) || ''}${cssName}: ${value};`;
721
+ },
722
+ };
723
+ }
724
+
725
+ /** Table nodes from prosemirror-tables, with cell background + email-layout support. */
661
726
  const tableNodeSpecs = tableNodes({
662
727
  tableGroup: 'block',
663
728
  cellContent: 'block+',
@@ -665,7 +730,13 @@ const tableNodeSpecs = tableNodes({
665
730
  background: {
666
731
  default: null,
667
732
  getFromDOM(dom) {
668
- return (dom as HTMLElement).style.backgroundColor || null;
733
+ // Fidelity stashes the cell background on a data-attr (so it never
734
+ // becomes a bg mark); legacy/non-fidelity content keeps it in the style.
735
+ return (
736
+ (dom as HTMLElement).getAttribute('data-cell-bg') ||
737
+ (dom as HTMLElement).style.backgroundColor ||
738
+ null
739
+ );
669
740
  },
670
741
  setDOMAttr(value, attrs) {
671
742
  if (value) {
@@ -673,6 +744,55 @@ const tableNodeSpecs = tableNodes({
673
744
  }
674
745
  },
675
746
  },
747
+ // Padding is read per side so partial shorthands round-trip.
748
+ paddingTop: cellStyleAttr('padding-top'),
749
+ paddingRight: cellStyleAttr('padding-right'),
750
+ paddingBottom: cellStyleAttr('padding-bottom'),
751
+ paddingLeft: cellStyleAttr('padding-left'),
752
+ width: cellStyleAttr('width'),
753
+ valign: cellStyleAttr('vertical-align'),
754
+ borderTop: cellStyleAttr('border-top'),
755
+ borderRight: cellStyleAttr('border-right'),
756
+ borderBottom: cellStyleAttr('border-bottom'),
757
+ borderLeft: cellStyleAttr('border-left'),
758
+ borderRadius: cellStyleAttr('border-radius'),
759
+ // Cell text colour/font, carried on a data-attr so it inherits through the
760
+ // cell's style instead of spawning a span on every text run.
761
+ textStyle: {
762
+ default: null,
763
+ getFromDOM(dom: HTMLElement) {
764
+ return dom.getAttribute('data-cell-text-style') || null;
765
+ },
766
+ setDOMAttr(value: unknown, attrs: Record<string, unknown>) {
767
+ const safe = sanitizeTableTextStyleForWrite(value as string);
768
+ if (safe) attrs.style = `${(attrs.style as string) || ''}${safe};`;
769
+ },
770
+ },
771
+ // Cell text-align, carried on data-cell-align (never the live style) so
772
+ // flag-off output is unchanged; validated against the keyword set on write.
773
+ textAlign: {
774
+ default: null,
775
+ getFromDOM(dom: HTMLElement) {
776
+ return dom.getAttribute('data-cell-align') || null;
777
+ },
778
+ setDOMAttr(value: unknown, attrs: Record<string, unknown>) {
779
+ const v = String(value ?? '').toLowerCase();
780
+ if (CELL_ALIGN_KEYWORDS.has(v)) {
781
+ attrs.style = `${(attrs.style as string) || ''}text-align: ${v};`;
782
+ }
783
+ },
784
+ },
785
+ // Per-app extension declarations, re-validated on write-back.
786
+ extraStyle: {
787
+ default: null,
788
+ getFromDOM(dom: HTMLElement) {
789
+ return dom.getAttribute('data-extra-style') || null;
790
+ },
791
+ setDOMAttr(value: unknown, attrs: Record<string, unknown>) {
792
+ const safe = sanitizeExtraStyleForWrite(value as string);
793
+ if (safe) attrs.style = `${(attrs.style as string) || ''}${safe};`;
794
+ },
795
+ },
676
796
  },
677
797
  });
678
798
 
@@ -682,22 +802,75 @@ const tableNodeSpecs = tableNodes({
682
802
  * borderless, with dashed guides visible only while editing.
683
803
  */
684
804
  const baseTableSpec = tableNodeSpecs.table;
805
+
806
+ /** Inline styles for a table's fidelity attrs; shared by toDOM and the live TableView. */
807
+ export function tableStyles(attrs: Record<string, unknown>): string[] {
808
+ const { width, maxWidth, background, border, align, textStyle, extraStyle } = attrs;
809
+ const styles: string[] = [];
810
+ if (width) styles.push(`width: ${width}`);
811
+ if (maxWidth) styles.push(`max-width: ${maxWidth}`);
812
+ if (background) styles.push(`background-color: ${background}`);
813
+ if (border) styles.push(`border: ${border}`);
814
+ if (align === 'center') styles.push('margin-left: auto', 'margin-right: auto');
815
+ // Table-level font/colour/line-height, re-validated on write-back (same
816
+ // validators as the sanitizer) so cells/paragraphs inherit it through CSS.
817
+ if (textStyle) {
818
+ const safe = sanitizeTableTextStyleForWrite(textStyle as string);
819
+ if (safe) styles.push(safe);
820
+ }
821
+ // Per-app extension declarations, re-validated against the permanent denylist
822
+ // + value grammar on write-back (the singleton schema can't see the allowlist).
823
+ if (extraStyle) {
824
+ const safe = sanitizeExtraStyleForWrite(extraStyle as string);
825
+ if (safe) styles.push(safe);
826
+ }
827
+ return styles;
828
+ }
685
829
  const tableSpec: NodeSpec = {
686
830
  ...baseTableSpec,
687
- attrs: { ...(baseTableSpec.attrs ?? {}), layout: { default: false } },
831
+ attrs: {
832
+ ...(baseTableSpec.attrs ?? {}),
833
+ layout: { default: false },
834
+ width: { default: null },
835
+ maxWidth: { default: null },
836
+ background: { default: null },
837
+ border: { default: null },
838
+ align: { default: null },
839
+ textStyle: { default: null },
840
+ extraStyle: { default: null },
841
+ },
688
842
  parseDOM: [
689
843
  {
690
844
  tag: 'table',
691
845
  getAttrs: (dom: HTMLElement) => ({
692
846
  layout:
693
847
  dom.getAttribute('role') === 'presentation' || dom.hasAttribute('data-layout'),
848
+ width: dom.style.width || null,
849
+ maxWidth: dom.style.maxWidth || null,
850
+ extraStyle: dom.getAttribute('data-extra-style') || null,
851
+ // Table font/colour comes only from the fidelity data-attr (so flag-off
852
+ // tables keep today's no-table-text-style behaviour).
853
+ textStyle: dom.getAttribute('data-table-text-style') || null,
854
+ // Table background comes only from the fidelity data-attr.
855
+ background: dom.getAttribute('data-table-bg') || null,
856
+ border: dom.style.border || null,
857
+ // Centring comes from the fidelity data-attr (email `align="center"`) or
858
+ // from auto side margins written back by toDOM.
859
+ align:
860
+ dom.getAttribute('data-table-align') === 'center' ||
861
+ (dom.style.marginLeft === 'auto' && dom.style.marginRight === 'auto')
862
+ ? 'center'
863
+ : null,
694
864
  }),
695
865
  },
696
866
  ],
697
867
  toDOM(node) {
698
- return node.attrs.layout
699
- ? ['table', { role: 'presentation', 'data-layout': 'true' }, ['tbody', 0]]
700
- : ['table', ['tbody', 0]];
868
+ const styles = tableStyles(node.attrs);
869
+ const attrs: Record<string, string> = node.attrs.layout
870
+ ? { role: 'presentation', 'data-layout': 'true' }
871
+ : {};
872
+ if (styles.length) attrs.style = styles.join('; ');
873
+ return ['table', attrs, ['tbody', 0]];
701
874
  },
702
875
  };
703
876
 
@@ -138,7 +138,9 @@ export function computeToolbarState(state: EditorState): ToolbarState {
138
138
  if (listStart === null) listStart = (node.attrs.order as number) ?? 1;
139
139
  } else if (node.type === schema.nodes.task_list) inTaskList = true;
140
140
  else if (node.type === schema.nodes.blockquote) inBlockquote = true;
141
- else if (node.type === schema.nodes.table) {
141
+ else if (node.type === schema.nodes.table && !inTable) {
142
+ // Innermost table wins: a data table nested in an email layout table
143
+ // is not a layout table.
142
144
  inTable = true;
143
145
  tableLayout = !!node.attrs.layout;
144
146
  }
@@ -5,7 +5,13 @@ import {
5
5
  Schema,
6
6
  Slice,
7
7
  } from 'prosemirror-model';
8
- import { sanitizeHtml } from './sanitize';
8
+ import { sanitizeHtml, relocateEmailContainers } from './sanitize';
9
+ import { NormalizedAllowedStyles } from './email-css';
10
+ import {
11
+ applyEmailRenderDefaults,
12
+ finishEmailTables,
13
+ EmailRenderDefaults,
14
+ } from './email-render';
9
15
 
10
16
  const parserCache = new WeakMap<Schema, PMDOMParser>();
11
17
  const serializerCache = new WeakMap<Schema, DOMSerializer>();
@@ -29,24 +35,40 @@ function getSerializer(schema: Schema): DOMSerializer {
29
35
  }
30
36
 
31
37
  /** Parses an HTML string into a document node, sanitizing by default. */
32
- export function htmlToDoc(schema: Schema, html: string, sanitize = true): PMNode {
33
- const clean = sanitize ? sanitizeHtml(html) : html;
38
+ export function htmlToDoc(
39
+ schema: Schema,
40
+ html: string,
41
+ sanitize = true,
42
+ options?: { emailFidelity?: boolean; allowedStyles?: NormalizedAllowedStyles }
43
+ ): PMNode {
44
+ let clean = sanitize ? sanitizeHtml(html, options) : html;
45
+ // Lift carried container background/font declarations onto node-attr data
46
+ // hooks so they don't become per-run marks (see relocateEmailContainers).
47
+ if (options?.emailFidelity) clean = relocateEmailContainers(clean);
34
48
  const dom = new DOMParser().parseFromString(`<body>${clean}</body>`, 'text/html');
35
49
  return getParser(schema).parse(dom.body);
36
50
  }
37
51
 
38
52
  /** Parses an HTML string into a slice suitable for replaceSelection. */
39
- export function htmlToSlice(schema: Schema, html: string, sanitize = true): Slice {
40
- const clean = sanitize ? sanitizeHtml(html) : html;
53
+ export function htmlToSlice(
54
+ schema: Schema,
55
+ html: string,
56
+ sanitize = true,
57
+ options?: { emailFidelity?: boolean; allowedStyles?: NormalizedAllowedStyles }
58
+ ): Slice {
59
+ let clean = sanitize ? sanitizeHtml(html, options) : html;
60
+ if (options?.emailFidelity) clean = relocateEmailContainers(clean);
41
61
  const dom = new DOMParser().parseFromString(`<body>${clean}</body>`, 'text/html');
42
62
  return getParser(schema).parseSlice(dom.body, { preserveWhitespace: true });
43
63
  }
44
64
 
45
- /** Serializes a document node back to an HTML string. */
46
- export function docToHtml(doc: PMNode): string {
65
+ /** Serializes a document to HTML; `emailDefaults` writes the editor's table rendering into it. */
66
+ export function docToHtml(doc: PMNode, emailDefaults?: EmailRenderDefaults): string {
47
67
  const schema = doc.type.schema;
68
+ const source = emailDefaults ? applyEmailRenderDefaults(doc, emailDefaults) : doc;
48
69
  const container = document.createElement('div');
49
- container.appendChild(getSerializer(schema).serializeFragment(doc.content));
70
+ container.appendChild(getSerializer(schema).serializeFragment(source.content));
71
+ if (emailDefaults) finishEmailTables(container);
50
72
  return container.innerHTML;
51
73
  }
52
74