@aquera/nile-elements 1.9.8 → 1.9.9

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 (232) hide show
  1. package/README.md +3 -0
  2. package/dist/{index-249de90a.esm.js → index-289706c7.esm.js} +1 -1
  3. package/dist/{index-df196058.cjs.js → index-d7e6f1c6.cjs.js} +2 -2
  4. package/dist/index-d7e6f1c6.cjs.js.map +1 -0
  5. package/dist/index.cjs.js +1 -1
  6. package/dist/index.esm.js +1 -1
  7. package/dist/index.js +1577 -1275
  8. package/dist/katex-44476ab4.esm.js +1 -0
  9. package/dist/katex-f4186f87.cjs.js +2 -0
  10. package/dist/katex-f4186f87.cjs.js.map +1 -0
  11. package/dist/nile-color-picker/index.cjs.js +1 -1
  12. package/dist/nile-color-picker/index.esm.js +1 -1
  13. package/dist/nile-color-picker/nile-color-picker.cjs.js +1 -1
  14. package/dist/nile-color-picker/nile-color-picker.cjs.js.map +1 -1
  15. package/dist/nile-color-picker/nile-color-picker.esm.js +1 -1
  16. package/dist/nile-wysiwyg-editor/engine/commands.cjs.js +1 -1
  17. package/dist/nile-wysiwyg-editor/engine/commands.cjs.js.map +1 -1
  18. package/dist/nile-wysiwyg-editor/engine/commands.esm.js +1 -1
  19. package/dist/nile-wysiwyg-editor/engine/create-state.cjs.js +1 -1
  20. package/dist/nile-wysiwyg-editor/engine/create-state.cjs.js.map +1 -1
  21. package/dist/nile-wysiwyg-editor/engine/create-state.esm.js +1 -1
  22. package/dist/nile-wysiwyg-editor/engine/index.cjs.js +1 -1
  23. package/dist/nile-wysiwyg-editor/engine/index.esm.js +1 -1
  24. package/dist/nile-wysiwyg-editor/engine/inputrules.cjs.js +1 -1
  25. package/dist/nile-wysiwyg-editor/engine/keymap.cjs.js +1 -1
  26. package/dist/nile-wysiwyg-editor/engine/keymap.esm.js +1 -1
  27. package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.cjs.js +1 -1
  28. package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.cjs.js.map +1 -1
  29. package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.esm.js +1 -1
  30. package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.cjs.js +1 -1
  31. package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.cjs.js.map +1 -1
  32. package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.esm.js +1 -1
  33. package/dist/nile-wysiwyg-editor/engine/plugins/embeds.cjs.js +1 -1
  34. package/dist/nile-wysiwyg-editor/engine/plugins/embeds.cjs.js.map +1 -1
  35. package/dist/nile-wysiwyg-editor/engine/plugins/embeds.esm.js +1 -1
  36. package/dist/nile-wysiwyg-editor/engine/plugins/math-view.cjs.js +1 -1
  37. package/dist/nile-wysiwyg-editor/engine/plugins/math-view.cjs.js.map +1 -1
  38. package/dist/nile-wysiwyg-editor/engine/plugins/math-view.esm.js +1 -1
  39. package/dist/nile-wysiwyg-editor/engine/plugins/style-block-view.cjs.js +2 -0
  40. package/dist/nile-wysiwyg-editor/engine/plugins/style-block-view.cjs.js.map +1 -0
  41. package/dist/nile-wysiwyg-editor/engine/plugins/style-block-view.esm.js +1 -0
  42. package/dist/nile-wysiwyg-editor/engine/plugins/tables.cjs.js +1 -1
  43. package/dist/nile-wysiwyg-editor/engine/plugins/tables.cjs.js.map +1 -1
  44. package/dist/nile-wysiwyg-editor/engine/plugins/tables.esm.js +1 -1
  45. package/dist/nile-wysiwyg-editor/engine/sanitize.cjs.js +1 -1
  46. package/dist/nile-wysiwyg-editor/engine/sanitize.cjs.js.map +1 -1
  47. package/dist/nile-wysiwyg-editor/engine/sanitize.esm.js +1 -1
  48. package/dist/nile-wysiwyg-editor/engine/schema.cjs.js +1 -1
  49. package/dist/nile-wysiwyg-editor/engine/schema.cjs.js.map +1 -1
  50. package/dist/nile-wysiwyg-editor/engine/schema.esm.js +1 -1
  51. package/dist/nile-wysiwyg-editor/engine/selection-state.cjs.js +1 -1
  52. package/dist/nile-wysiwyg-editor/engine/selection-state.cjs.js.map +1 -1
  53. package/dist/nile-wysiwyg-editor/engine/selection-state.esm.js +1 -1
  54. package/dist/nile-wysiwyg-editor/index.cjs.js +1 -1
  55. package/dist/nile-wysiwyg-editor/index.esm.js +1 -1
  56. package/dist/nile-wysiwyg-editor/math/katex-renderer.cjs.js +2 -0
  57. package/dist/nile-wysiwyg-editor/math/katex-renderer.cjs.js.map +1 -0
  58. package/dist/nile-wysiwyg-editor/math/katex-renderer.esm.js +1 -0
  59. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js +1 -1
  60. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js.map +1 -1
  61. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.cjs.js +1 -1
  62. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.cjs.js.map +1 -1
  63. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.esm.js +22 -3
  64. package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.esm.js +7 -6
  65. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.cjs.js +1 -1
  66. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.esm.js +1 -1
  67. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.cjs.js +2 -0
  68. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.cjs.js.map +1 -0
  69. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.esm.js +1 -0
  70. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.cjs.js +1 -1
  71. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.cjs.js.map +1 -1
  72. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.css.cjs.js +1 -1
  73. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.css.cjs.js.map +1 -1
  74. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.css.esm.js +33 -54
  75. package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.esm.js +83 -95
  76. package/dist/nile-wysiwyg-editor/types.cjs.js +1 -1
  77. package/dist/nile-wysiwyg-editor/types.cjs.js.map +1 -1
  78. package/dist/nile-wysiwyg-editor/types.esm.js +1 -1
  79. package/dist/nile-wysiwyg-editor/ui/bubble-item.cjs.js +2 -0
  80. package/dist/nile-wysiwyg-editor/ui/bubble-item.cjs.js.map +1 -0
  81. package/dist/nile-wysiwyg-editor/ui/bubble-item.esm.js +1 -0
  82. package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js +1 -1
  83. package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js.map +1 -1
  84. package/dist/nile-wysiwyg-editor/ui/bubble-menu.esm.js +23 -15
  85. package/dist/nile-wysiwyg-editor/ui/code-block-menu.cjs.js +1 -1
  86. package/dist/nile-wysiwyg-editor/ui/code-block-menu.cjs.js.map +1 -1
  87. package/dist/nile-wysiwyg-editor/ui/code-block-menu.esm.js +3 -3
  88. package/dist/nile-wysiwyg-editor/ui/embed-panel.cjs.js +1 -1
  89. package/dist/nile-wysiwyg-editor/ui/embed-panel.cjs.js.map +1 -1
  90. package/dist/nile-wysiwyg-editor/ui/embed-panel.esm.js +2 -2
  91. package/dist/nile-wysiwyg-editor/ui/math-panel.cjs.js +1 -1
  92. package/dist/nile-wysiwyg-editor/ui/math-panel.cjs.js.map +1 -1
  93. package/dist/nile-wysiwyg-editor/ui/math-panel.esm.js +0 -3
  94. package/dist/nile-wysiwyg-editor/ui/preview.cjs.js +2 -0
  95. package/dist/nile-wysiwyg-editor/ui/preview.cjs.js.map +1 -0
  96. package/dist/nile-wysiwyg-editor/ui/preview.esm.js +8 -0
  97. package/dist/nile-wysiwyg-editor/ui/source-view.cjs.js +1 -1
  98. package/dist/nile-wysiwyg-editor/ui/source-view.cjs.js.map +1 -1
  99. package/dist/nile-wysiwyg-editor/ui/source-view.esm.js +225 -24
  100. package/dist/nile-wysiwyg-editor/ui/suggest-list.cjs.js +1 -1
  101. package/dist/nile-wysiwyg-editor/ui/suggest-list.cjs.js.map +1 -1
  102. package/dist/nile-wysiwyg-editor/ui/suggest-list.esm.js +9 -9
  103. package/dist/nile-wysiwyg-editor/ui/table-grid-picker.cjs.js +1 -1
  104. package/dist/nile-wysiwyg-editor/ui/table-grid-picker.cjs.js.map +1 -1
  105. package/dist/nile-wysiwyg-editor/ui/table-grid-picker.esm.js +115 -13
  106. package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js +1 -1
  107. package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js.map +1 -1
  108. package/dist/nile-wysiwyg-editor/ui/table-menu.esm.js +13 -12
  109. package/dist/src/index.d.ts +5 -0
  110. package/dist/src/index.js +3 -0
  111. package/dist/src/index.js.map +1 -1
  112. package/dist/src/nile-color-picker/nile-color-picker.d.ts +1 -0
  113. package/dist/src/nile-color-picker/nile-color-picker.js +1 -0
  114. package/dist/src/nile-color-picker/nile-color-picker.js.map +1 -1
  115. package/dist/src/nile-wysiwyg-editor/engine/index.d.ts +1 -0
  116. package/dist/src/nile-wysiwyg-editor/engine/index.js +1 -0
  117. package/dist/src/nile-wysiwyg-editor/engine/index.js.map +1 -1
  118. package/dist/src/nile-wysiwyg-editor/engine/plugins/embed-view.js +3 -0
  119. package/dist/src/nile-wysiwyg-editor/engine/plugins/embed-view.js.map +1 -1
  120. package/dist/src/nile-wysiwyg-editor/engine/plugins/embeds.d.ts +19 -4
  121. package/dist/src/nile-wysiwyg-editor/engine/plugins/embeds.js +23 -18
  122. package/dist/src/nile-wysiwyg-editor/engine/plugins/embeds.js.map +1 -1
  123. package/dist/src/nile-wysiwyg-editor/engine/plugins/math-view.d.ts +8 -3
  124. package/dist/src/nile-wysiwyg-editor/engine/plugins/math-view.js +41 -4
  125. package/dist/src/nile-wysiwyg-editor/engine/plugins/math-view.js.map +1 -1
  126. package/dist/src/nile-wysiwyg-editor/engine/plugins/style-block-view.d.ts +17 -0
  127. package/dist/src/nile-wysiwyg-editor/engine/plugins/style-block-view.js +174 -0
  128. package/dist/src/nile-wysiwyg-editor/engine/plugins/style-block-view.js.map +1 -0
  129. package/dist/src/nile-wysiwyg-editor/engine/plugins/tables.js +33 -2
  130. package/dist/src/nile-wysiwyg-editor/engine/plugins/tables.js.map +1 -1
  131. package/dist/src/nile-wysiwyg-editor/engine/pm.test.js +49 -8
  132. package/dist/src/nile-wysiwyg-editor/engine/pm.test.js.map +1 -1
  133. package/dist/src/nile-wysiwyg-editor/engine/sanitize.d.ts +12 -0
  134. package/dist/src/nile-wysiwyg-editor/engine/sanitize.js +76 -8
  135. package/dist/src/nile-wysiwyg-editor/engine/sanitize.js.map +1 -1
  136. package/dist/src/nile-wysiwyg-editor/engine/schema.d.ts +2 -0
  137. package/dist/src/nile-wysiwyg-editor/engine/schema.js +154 -2
  138. package/dist/src/nile-wysiwyg-editor/engine/schema.js.map +1 -1
  139. package/dist/src/nile-wysiwyg-editor/index.d.ts +5 -0
  140. package/dist/src/nile-wysiwyg-editor/index.js +3 -0
  141. package/dist/src/nile-wysiwyg-editor/index.js.map +1 -1
  142. package/dist/src/nile-wysiwyg-editor/math/katex-renderer.d.ts +38 -0
  143. package/dist/src/nile-wysiwyg-editor/math/katex-renderer.js +40 -0
  144. package/dist/src/nile-wysiwyg-editor/math/katex-renderer.js.map +1 -0
  145. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.js +22 -3
  146. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.js.map +1 -1
  147. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.d.ts +36 -0
  148. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.js +125 -8
  149. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.js.map +1 -1
  150. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.js +5 -2
  151. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.js.map +1 -1
  152. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.d.ts +2 -0
  153. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.js +1 -0
  154. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.js.map +1 -1
  155. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.d.ts +55 -0
  156. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.js +79 -0
  157. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.js.map +1 -0
  158. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.css.js +33 -54
  159. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.css.js.map +1 -1
  160. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.d.ts +50 -2
  161. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.js +158 -102
  162. package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.js.map +1 -1
  163. package/dist/src/nile-wysiwyg-editor/types.d.ts +4 -2
  164. package/dist/src/nile-wysiwyg-editor/types.js +2 -2
  165. package/dist/src/nile-wysiwyg-editor/types.js.map +1 -1
  166. package/dist/src/nile-wysiwyg-editor/ui/bubble-item.d.ts +48 -0
  167. package/dist/src/nile-wysiwyg-editor/ui/bubble-item.js +69 -0
  168. package/dist/src/nile-wysiwyg-editor/ui/bubble-item.js.map +1 -0
  169. package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.d.ts +17 -2
  170. package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.js +128 -35
  171. package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.js.map +1 -1
  172. package/dist/src/nile-wysiwyg-editor/ui/embed-panel.d.ts +2 -1
  173. package/dist/src/nile-wysiwyg-editor/ui/embed-panel.js +4 -3
  174. package/dist/src/nile-wysiwyg-editor/ui/embed-panel.js.map +1 -1
  175. package/dist/src/nile-wysiwyg-editor/ui/math-panel.js +0 -3
  176. package/dist/src/nile-wysiwyg-editor/ui/math-panel.js.map +1 -1
  177. package/dist/src/nile-wysiwyg-editor/ui/preview.d.ts +20 -0
  178. package/dist/src/nile-wysiwyg-editor/ui/preview.js +44 -0
  179. package/dist/src/nile-wysiwyg-editor/ui/preview.js.map +1 -0
  180. package/dist/src/nile-wysiwyg-editor/ui/source-view.d.ts +35 -3
  181. package/dist/src/nile-wysiwyg-editor/ui/source-view.js +337 -24
  182. package/dist/src/nile-wysiwyg-editor/ui/source-view.js.map +1 -1
  183. package/dist/src/nile-wysiwyg-editor/ui/suggest-list.d.ts +1 -0
  184. package/dist/src/nile-wysiwyg-editor/ui/suggest-list.js +9 -0
  185. package/dist/src/nile-wysiwyg-editor/ui/suggest-list.js.map +1 -1
  186. package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.d.ts +13 -2
  187. package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.js +166 -10
  188. package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.js.map +1 -1
  189. package/dist/src/nile-wysiwyg-editor/ui/table-menu.d.ts +1 -0
  190. package/dist/src/nile-wysiwyg-editor/ui/table-menu.js +10 -8
  191. package/dist/src/nile-wysiwyg-editor/ui/table-menu.js.map +1 -1
  192. package/dist/src/version.js +1 -1
  193. package/dist/src/version.js.map +1 -1
  194. package/dist/tsconfig.tsbuildinfo +1 -1
  195. package/dist/xml-25c4108a.esm.js +1 -0
  196. package/dist/xml-90fd974e.cjs.js +2 -0
  197. package/dist/xml-90fd974e.cjs.js.map +1 -0
  198. package/package.json +2 -1
  199. package/rollup.config.js +1 -0
  200. package/src/index.ts +8 -0
  201. package/src/nile-color-picker/nile-color-picker.ts +1 -0
  202. package/src/nile-wysiwyg-editor/engine/index.ts +1 -0
  203. package/src/nile-wysiwyg-editor/engine/plugins/embed-view.ts +3 -0
  204. package/src/nile-wysiwyg-editor/engine/plugins/embeds.ts +26 -20
  205. package/src/nile-wysiwyg-editor/engine/plugins/math-view.ts +45 -4
  206. package/src/nile-wysiwyg-editor/engine/plugins/style-block-view.ts +178 -0
  207. package/src/nile-wysiwyg-editor/engine/plugins/tables.ts +34 -2
  208. package/src/nile-wysiwyg-editor/engine/pm.test.ts +58 -8
  209. package/src/nile-wysiwyg-editor/engine/sanitize.ts +71 -8
  210. package/src/nile-wysiwyg-editor/engine/schema.ts +158 -7
  211. package/src/nile-wysiwyg-editor/index.ts +5 -0
  212. package/src/nile-wysiwyg-editor/math/katex-renderer.ts +59 -0
  213. package/src/nile-wysiwyg-editor/math/katex.d.ts +17 -0
  214. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.ts +22 -3
  215. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.ts +5 -2
  216. package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.ts +142 -7
  217. package/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.ts +2 -0
  218. package/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar-item.ts +68 -0
  219. package/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.css.ts +33 -54
  220. package/src/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.ts +202 -108
  221. package/src/nile-wysiwyg-editor/types.ts +6 -4
  222. package/src/nile-wysiwyg-editor/ui/bubble-item.ts +60 -0
  223. package/src/nile-wysiwyg-editor/ui/bubble-menu.ts +147 -40
  224. package/src/nile-wysiwyg-editor/ui/embed-panel.ts +4 -3
  225. package/src/nile-wysiwyg-editor/ui/math-panel.ts +0 -3
  226. package/src/nile-wysiwyg-editor/ui/preview.ts +42 -0
  227. package/src/nile-wysiwyg-editor/ui/source-view.ts +339 -31
  228. package/src/nile-wysiwyg-editor/ui/suggest-list.ts +10 -0
  229. package/src/nile-wysiwyg-editor/ui/table-grid-picker.ts +160 -10
  230. package/src/nile-wysiwyg-editor/ui/table-menu.ts +10 -8
  231. package/vscode-html-custom-data.json +75 -6
  232. package/dist/index-df196058.cjs.js.map +0 -1
@@ -0,0 +1,174 @@
1
+ /** Content root the editor mounts the document under. Author CSS is scoped to
2
+ * it so a rule such as `div { background: green }` styles the content only and
3
+ * can never paint the editor chrome (toolbar, panels, surface) that shares the
4
+ * same shadow root. */
5
+ const CONTENT_SCOPE = '.ProseMirror';
6
+ /** Advances past a quoted string starting at `i` (the opening quote), honoring
7
+ * backslash escapes; returns the index just after the closing quote. */
8
+ function skipString(css, i) {
9
+ const quote = css[i];
10
+ i += 1;
11
+ while (i < css.length) {
12
+ if (css[i] === '\\') {
13
+ i += 2;
14
+ continue;
15
+ }
16
+ if (css[i] === quote)
17
+ return i + 1;
18
+ i += 1;
19
+ }
20
+ return i;
21
+ }
22
+ /** Splits on a top-level separator, ignoring ones inside (), [] or strings. */
23
+ function splitTopLevel(str, sep) {
24
+ const parts = [];
25
+ let depth = 0;
26
+ let buf = '';
27
+ for (let i = 0; i < str.length; i += 1) {
28
+ const c = str[i];
29
+ if (c === '"' || c === "'") {
30
+ const end = skipString(str, i);
31
+ buf += str.slice(i, end);
32
+ i = end - 1;
33
+ continue;
34
+ }
35
+ if (c === '(' || c === '[')
36
+ depth += 1;
37
+ else if (c === ')' || c === ']')
38
+ depth -= 1;
39
+ if (c === sep && depth === 0) {
40
+ parts.push(buf);
41
+ buf = '';
42
+ continue;
43
+ }
44
+ buf += c;
45
+ }
46
+ parts.push(buf);
47
+ return parts;
48
+ }
49
+ /** Confines one complex selector to the content root. `html`/`body`/`:root`
50
+ * map onto the root itself. */
51
+ function scopeSelector(selector, scope) {
52
+ const sel = selector.trim();
53
+ if (!sel)
54
+ return sel;
55
+ if (/^(?:html|body|:root)$/i.test(sel))
56
+ return scope;
57
+ const root = sel.match(/^(?:html|body|:root)\b\s*/i);
58
+ return root ? `${scope} ${sel.slice(root[0].length)}`.trim() : `${scope} ${sel}`;
59
+ }
60
+ /** Confines a comma-separated selector list to the content root. */
61
+ function scopeSelectorList(list, scope) {
62
+ return splitTopLevel(list, ',')
63
+ .map(part => scopeSelector(part, scope))
64
+ .filter(Boolean)
65
+ .join(', ');
66
+ }
67
+ const NESTED_AT_RULES = new Set(['media', 'supports', 'container', 'layer', 'scope']);
68
+ /**
69
+ * Scopes every rule in a CSS block to the content root by prefixing selectors,
70
+ * keeping each declaration block **verbatim**. Declarations are never re-parsed
71
+ * (a CSSOM round-trip drops `var()` inside shorthands, e.g. gradient text), and
72
+ * strings/nested braces are tracked so `content: "}"` can't derail it. Nested
73
+ * conditionals (`@media`, `@supports`, …) recurse; other at-rules
74
+ * (`@keyframes`, `@font-face`, …) pass through untouched.
75
+ */
76
+ function scopeBlock(css, scope) {
77
+ let out = '';
78
+ let i = 0;
79
+ const n = css.length;
80
+ while (i < n) {
81
+ let j = i;
82
+ while (j < n) {
83
+ const c = css[j];
84
+ if (c === '"' || c === "'") {
85
+ j = skipString(css, j);
86
+ continue;
87
+ }
88
+ if (c === '{' || c === ';')
89
+ break;
90
+ j += 1;
91
+ }
92
+ if (j >= n) {
93
+ out += css.slice(i);
94
+ break;
95
+ }
96
+ if (css[j] === ';') {
97
+ // A statement at-rule (e.g. a stray @charset) — keep verbatim.
98
+ out += css.slice(i, j + 1);
99
+ i = j + 1;
100
+ continue;
101
+ }
102
+ const prelude = css.slice(i, j).trim();
103
+ let depth = 1;
104
+ let k = j + 1;
105
+ while (k < n && depth > 0) {
106
+ const c = css[k];
107
+ if (c === '"' || c === "'") {
108
+ k = skipString(css, k);
109
+ continue;
110
+ }
111
+ if (c === '{')
112
+ depth += 1;
113
+ else if (c === '}')
114
+ depth -= 1;
115
+ k += 1;
116
+ }
117
+ const body = css.slice(j + 1, k - 1);
118
+ if (prelude.startsWith('@')) {
119
+ const name = (prelude.match(/^@([a-z-]+)/i)?.[1] ?? '').toLowerCase();
120
+ out += NESTED_AT_RULES.has(name)
121
+ ? `${prelude} {${scopeBlock(body, scope)}}`
122
+ : `${prelude} {${body}}`;
123
+ }
124
+ else if (prelude) {
125
+ out += `${scopeSelectorList(prelude, scope)} {${body}}`;
126
+ }
127
+ i = k;
128
+ }
129
+ return out;
130
+ }
131
+ /** Returns author CSS confined to the content root. */
132
+ function scopeCss(css, scope) {
133
+ if (!css.trim())
134
+ return '';
135
+ try {
136
+ return scopeBlock(css, scope);
137
+ }
138
+ catch {
139
+ return css;
140
+ }
141
+ }
142
+ /**
143
+ * Node view for an author `<style>` block. It injects the CSS live — scoped to
144
+ * the content root — so the styles apply to the document as authored, with no
145
+ * visible chip. The block itself renders nothing (a hidden `<style>` host); it
146
+ * round-trips to `<style>` in the output via the schema's toDOM, and the same
147
+ * raw CSS is what the HTML-source preview renders.
148
+ */
149
+ export class StyleBlockView {
150
+ constructor(node) {
151
+ this.node = node;
152
+ this.dom = document.createElement('div');
153
+ this.dom.className = 'nile-wysiwyg__style-block';
154
+ this.dom.contentEditable = 'false';
155
+ // A <style> applies regardless of its (display:none) host, so the block is
156
+ // invisible yet its rules take effect on the content.
157
+ this.styleEl = document.createElement('style');
158
+ this.styleEl.textContent = scopeCss(node.attrs.css, CONTENT_SCOPE);
159
+ this.dom.append(this.styleEl);
160
+ }
161
+ update(node) {
162
+ if (node.type !== this.node.type)
163
+ return false;
164
+ if (node.attrs.css !== this.node.attrs.css) {
165
+ this.styleEl.textContent = scopeCss(node.attrs.css, CONTENT_SCOPE);
166
+ }
167
+ this.node = node;
168
+ return true;
169
+ }
170
+ ignoreMutation() {
171
+ return true;
172
+ }
173
+ }
174
+ //# sourceMappingURL=style-block-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-block-view.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/style-block-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { Node as PMNode } from 'prosemirror-model';\nimport { NodeView } from 'prosemirror-view';\n\n/** Content root the editor mounts the document under. Author CSS is scoped to\n * it so a rule such as `div { background: green }` styles the content only and\n * can never paint the editor chrome (toolbar, panels, surface) that shares the\n * same shadow root. */\nconst CONTENT_SCOPE = '.ProseMirror';\n\n/** Advances past a quoted string starting at `i` (the opening quote), honoring\n * backslash escapes; returns the index just after the closing quote. */\nfunction skipString(css: string, i: number): number {\n const quote = css[i];\n i += 1;\n while (i < css.length) {\n if (css[i] === '\\\\') {\n i += 2;\n continue;\n }\n if (css[i] === quote) return i + 1;\n i += 1;\n }\n return i;\n}\n\n/** Splits on a top-level separator, ignoring ones inside (), [] or strings. */\nfunction splitTopLevel(str: string, sep: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let buf = '';\n for (let i = 0; i < str.length; i += 1) {\n const c = str[i];\n if (c === '\"' || c === \"'\") {\n const end = skipString(str, i);\n buf += str.slice(i, end);\n i = end - 1;\n continue;\n }\n if (c === '(' || c === '[') depth += 1;\n else if (c === ')' || c === ']') depth -= 1;\n if (c === sep && depth === 0) {\n parts.push(buf);\n buf = '';\n continue;\n }\n buf += c;\n }\n parts.push(buf);\n return parts;\n}\n\n/** Confines one complex selector to the content root. `html`/`body`/`:root`\n * map onto the root itself. */\nfunction scopeSelector(selector: string, scope: string): string {\n const sel = selector.trim();\n if (!sel) return sel;\n if (/^(?:html|body|:root)$/i.test(sel)) return scope;\n const root = sel.match(/^(?:html|body|:root)\\b\\s*/i);\n return root ? `${scope} ${sel.slice(root[0].length)}`.trim() : `${scope} ${sel}`;\n}\n\n/** Confines a comma-separated selector list to the content root. */\nfunction scopeSelectorList(list: string, scope: string): string {\n return splitTopLevel(list, ',')\n .map(part => scopeSelector(part, scope))\n .filter(Boolean)\n .join(', ');\n}\n\nconst NESTED_AT_RULES = new Set(['media', 'supports', 'container', 'layer', 'scope']);\n\n/**\n * Scopes every rule in a CSS block to the content root by prefixing selectors,\n * keeping each declaration block **verbatim**. Declarations are never re-parsed\n * (a CSSOM round-trip drops `var()` inside shorthands, e.g. gradient text), and\n * strings/nested braces are tracked so `content: \"}\"` can't derail it. Nested\n * conditionals (`@media`, `@supports`, …) recurse; other at-rules\n * (`@keyframes`, `@font-face`, …) pass through untouched.\n */\nfunction scopeBlock(css: string, scope: string): string {\n let out = '';\n let i = 0;\n const n = css.length;\n while (i < n) {\n let j = i;\n while (j < n) {\n const c = css[j];\n if (c === '\"' || c === \"'\") {\n j = skipString(css, j);\n continue;\n }\n if (c === '{' || c === ';') break;\n j += 1;\n }\n if (j >= n) {\n out += css.slice(i);\n break;\n }\n if (css[j] === ';') {\n // A statement at-rule (e.g. a stray @charset) — keep verbatim.\n out += css.slice(i, j + 1);\n i = j + 1;\n continue;\n }\n const prelude = css.slice(i, j).trim();\n let depth = 1;\n let k = j + 1;\n while (k < n && depth > 0) {\n const c = css[k];\n if (c === '\"' || c === \"'\") {\n k = skipString(css, k);\n continue;\n }\n if (c === '{') depth += 1;\n else if (c === '}') depth -= 1;\n k += 1;\n }\n const body = css.slice(j + 1, k - 1);\n if (prelude.startsWith('@')) {\n const name = (prelude.match(/^@([a-z-]+)/i)?.[1] ?? '').toLowerCase();\n out += NESTED_AT_RULES.has(name)\n ? `${prelude} {${scopeBlock(body, scope)}}`\n : `${prelude} {${body}}`;\n } else if (prelude) {\n out += `${scopeSelectorList(prelude, scope)} {${body}}`;\n }\n i = k;\n }\n return out;\n}\n\n/** Returns author CSS confined to the content root. */\nfunction scopeCss(css: string, scope: string): string {\n if (!css.trim()) return '';\n try {\n return scopeBlock(css, scope);\n } catch {\n return css;\n }\n}\n\n/**\n * Node view for an author `<style>` block. It injects the CSS live — scoped to\n * the content root — so the styles apply to the document as authored, with no\n * visible chip. The block itself renders nothing (a hidden `<style>` host); it\n * round-trips to `<style>` in the output via the schema's toDOM, and the same\n * raw CSS is what the HTML-source preview renders.\n */\nexport class StyleBlockView implements NodeView {\n dom: HTMLElement;\n\n private styleEl: HTMLStyleElement;\n\n constructor(private node: PMNode) {\n this.dom = document.createElement('div');\n this.dom.className = 'nile-wysiwyg__style-block';\n this.dom.contentEditable = 'false';\n\n // A <style> applies regardless of its (display:none) host, so the block is\n // invisible yet its rules take effect on the content.\n this.styleEl = document.createElement('style');\n this.styleEl.textContent = scopeCss(node.attrs.css, CONTENT_SCOPE);\n this.dom.append(this.styleEl);\n }\n\n update(node: PMNode): boolean {\n if (node.type !== this.node.type) return false;\n if (node.attrs.css !== this.node.attrs.css) {\n this.styleEl.textContent = scopeCss(node.attrs.css, CONTENT_SCOPE);\n }\n this.node = node;\n return true;\n }\n\n ignoreMutation(): boolean {\n return true;\n }\n}\n"]}
@@ -1,4 +1,32 @@
1
- import { tableEditing, columnResizing } from 'prosemirror-tables';
1
+ import { tableEditing, columnResizing, TableView } from 'prosemirror-tables';
2
+ /**
3
+ * TableView that also reflects the author's `class`/`id` onto the inner
4
+ * `<table>` element (the base TableView leaves it bare and puts its own class on
5
+ * the wrapper div). The attributes round-trip via the schema's toDOM on export;
6
+ * this makes `table.grid …` style rules match in the live editor too. Passed to
7
+ * `columnResizing` as its `View`, so column resizing keeps working.
8
+ */
9
+ class HtmlAttrTableView extends TableView {
10
+ constructor(node, defaultCellMinWidth) {
11
+ super(node, defaultCellMinWidth);
12
+ this.applyHtmlAttrs(node);
13
+ }
14
+ applyHtmlAttrs(node) {
15
+ const htmlClass = node.attrs.htmlClass;
16
+ const htmlId = node.attrs.htmlId;
17
+ this.table.className = htmlClass ?? '';
18
+ if (htmlId)
19
+ this.table.id = htmlId;
20
+ else
21
+ this.table.removeAttribute('id');
22
+ }
23
+ update(node) {
24
+ const updated = super.update(node);
25
+ if (updated)
26
+ this.applyHtmlAttrs(node);
27
+ return updated;
28
+ }
29
+ }
2
30
  /**
3
31
  * prosemirror-tables wiring: cell selections, fix-tables normalization, and
4
32
  * draggable column resizing (widths persist as `data-colwidth`). The CSS
@@ -6,6 +34,9 @@ import { tableEditing, columnResizing } from 'prosemirror-tables';
6
34
  * is inlined in nile-wysiwyg-editor.css.ts.
7
35
  */
8
36
  export function tablePlugins() {
9
- return [columnResizing(), tableEditing({ allowTableNodeSelection: true })];
37
+ return [
38
+ columnResizing({ View: HtmlAttrTableView }),
39
+ tableEditing({ allowTableNodeSelection: true }),
40
+ ];
10
41
  }
11
42
  //# sourceMappingURL=tables.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/tables.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAElE;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,cAAc,EAAE,EAAE,YAAY,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["import { Plugin } from 'prosemirror-state';\nimport { tableEditing, columnResizing } from 'prosemirror-tables';\n\n/**\n * prosemirror-tables wiring: cell selections, fix-tables normalization, and\n * draggable column resizing (widths persist as `data-colwidth`). The CSS\n * these plugins rely on (.selectedCell, .column-resize-handle, .resize-cursor)\n * is inlined in nile-wysiwyg-editor.css.ts.\n */\nexport function tablePlugins(): Plugin[] {\n return [columnResizing(), tableEditing({ allowTableNodeSelection: true })];\n}\n"]}
1
+ {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/tables.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;;;;GAMG;AACH,MAAM,iBAAkB,SAAQ,SAAS;IACvC,YAAY,IAAY,EAAE,mBAA2B;QACnD,KAAK,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QACjC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAEO,cAAc,CAAC,IAAY;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAA0B,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAuB,CAAC;QAClD,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,SAAS,IAAI,EAAE,CAAC;QACvC,IAAI,MAAM;YAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC;;YAC9B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,OAAO;YAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,cAAc,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAC3C,YAAY,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC","sourcesContent":["import { Plugin } from 'prosemirror-state';\nimport { Node as PMNode } from 'prosemirror-model';\nimport { tableEditing, columnResizing, TableView } from 'prosemirror-tables';\n\n/**\n * TableView that also reflects the author's `class`/`id` onto the inner\n * `<table>` element (the base TableView leaves it bare and puts its own class on\n * the wrapper div). The attributes round-trip via the schema's toDOM on export;\n * this makes `table.grid …` style rules match in the live editor too. Passed to\n * `columnResizing` as its `View`, so column resizing keeps working.\n */\nclass HtmlAttrTableView extends TableView {\n constructor(node: PMNode, defaultCellMinWidth: number) {\n super(node, defaultCellMinWidth);\n this.applyHtmlAttrs(node);\n }\n\n private applyHtmlAttrs(node: PMNode): void {\n const htmlClass = node.attrs.htmlClass as string | null;\n const htmlId = node.attrs.htmlId as string | null;\n this.table.className = htmlClass ?? '';\n if (htmlId) this.table.id = htmlId;\n else this.table.removeAttribute('id');\n }\n\n update(node: PMNode): boolean {\n const updated = super.update(node);\n if (updated) this.applyHtmlAttrs(node);\n return updated;\n }\n}\n\n/**\n * prosemirror-tables wiring: cell selections, fix-tables normalization, and\n * draggable column resizing (widths persist as `data-colwidth`). The CSS\n * these plugins rely on (.selectedCell, .column-resize-handle, .resize-cursor)\n * is inlined in nile-wysiwyg-editor.css.ts.\n */\nexport function tablePlugins(): Plugin[] {\n return [\n columnResizing({ View: HtmlAttrTableView }),\n tableEditing({ allowTableNodeSelection: true }),\n ];\n}\n"]}
@@ -36,10 +36,26 @@ describe('sanitizeHtml', () => {
36
36
  it('unwraps unknown elements but keeps their content', () => {
37
37
  expect(sanitizeHtml('<article><p>kept</p></article>')).to.equal('<p>kept</p>');
38
38
  });
39
- it('drops iframes, styles and forms with content', () => {
40
- const out = sanitizeHtml('<iframe src="x"></iframe><style>p{}</style><form><input></form><p>ok</p>');
39
+ it('drops non-https iframes and forms with content', () => {
40
+ const out = sanitizeHtml('<iframe src="x"></iframe><form><input></form><p>ok</p>');
41
41
  expect(out).to.equal('<p>ok</p>');
42
42
  });
43
+ it('keeps <style> blocks and sanitizes their CSS', () => {
44
+ const out = sanitizeHtml('<style>@import url("http://evil/x.css"); p{color:red} a{behavior:url(x.htc)} ' +
45
+ 'b{width:expression(alert(1))} c{background:url(http://evil/x.png)}</style><p>ok</p>');
46
+ expect(out).to.include('<style>');
47
+ expect(out).to.include('color:red');
48
+ expect(out).to.include('<p>ok</p>');
49
+ expect(out).to.not.match(/@import/i);
50
+ expect(out).to.not.match(/expression\s*\(/i);
51
+ expect(out).to.not.match(/behavior\s*:/i);
52
+ expect(out).to.not.match(/url\(\s*['"]?http/i);
53
+ });
54
+ it('keeps safe data-image and #fragment url() in <style>', () => {
55
+ const out = sanitizeHtml('<style>a{background:url(data:image/png;base64,AAAA)} b{clip-path:url(#f)}</style>');
56
+ expect(out).to.include('url(data:image/png');
57
+ expect(out).to.include('url(#f)');
58
+ });
43
59
  });
44
60
  describe('serializer round-trip', () => {
45
61
  const cases = [
@@ -67,6 +83,18 @@ describe('serializer round-trip', () => {
67
83
  const doc = htmlToDoc(defaultSchema, '<p><span style="font-weight: 700">x</span></p>');
68
84
  expect(docToHtml(doc)).to.include('<strong>');
69
85
  });
86
+ it('round-trips an author <style> block through the schema', () => {
87
+ const doc = htmlToDoc(defaultSchema, '<style>p{color:red}</style><p>hi</p>');
88
+ expect(doc.firstChild.type.name).to.equal('styleBlock');
89
+ const out = docToHtml(doc);
90
+ expect(out).to.include('<style>');
91
+ expect(out).to.match(/color:\s*red/i);
92
+ expect(out).to.include('<p>hi</p>');
93
+ // Malicious CSS is neutralized on the round-trip, not just at the surface.
94
+ const evil = docToHtml(htmlToDoc(defaultSchema, '<style>@import url(http://evil);x{color:blue}</style><p>ok</p>'));
95
+ expect(evil).to.include('<style>');
96
+ expect(evil).to.not.match(/@import/i);
97
+ });
70
98
  it('detects empty documents', () => {
71
99
  expect(isDocEmpty(htmlToDoc(defaultSchema, ''))).to.equal(true);
72
100
  expect(isDocEmpty(htmlToDoc(defaultSchema, '<p></p>'))).to.equal(true);
@@ -385,17 +413,30 @@ describe('embeds', () => {
385
413
  });
386
414
  expect(toEmbedUrl('https://www.loom.com/share/abcdef0123456789abcdef0123456789').provider).to.equal('loom');
387
415
  });
388
- it('rejects non-provider and non-https URLs', () => {
389
- expect(toEmbedUrl('https://evil.example.com/embed/x')).to.equal(null);
416
+ it('accepts any https URL as a generic embed, rejects non-https', () => {
417
+ expect(toEmbedUrl('https://example.com/player/x')).to.deep.equal({
418
+ src: 'https://example.com/player/x',
419
+ provider: 'generic',
420
+ });
421
+ // Lookalike hosts are no longer canonicalized as a provider, just generic.
422
+ expect(toEmbedUrl('https://youtube.com.evil.com/watch?v=x').provider).to.equal('generic');
423
+ // Non-https is still refused.
390
424
  expect(toEmbedUrl('http://www.youtube.com/watch?v=dQw4w9WgXcQ')).to.equal(null);
391
425
  expect(toEmbedUrl('javascript:alert(1)')).to.equal(null);
392
- expect(toEmbedUrl('https://youtube.com.evil.com/watch?v=x')).to.equal(null);
393
- expect(isAllowedEmbedSrc('https://evil.com/embed/x')).to.equal(false);
426
+ expect(isAllowedEmbedSrc('https://example.com/player/x')).to.equal(true);
427
+ expect(isAllowedEmbedSrc('http://example.com/x')).to.equal(false);
394
428
  });
395
- it('keeps allowlisted iframes through sanitization, drops the rest', () => {
429
+ it('keeps any https iframe through sanitization but force-sandboxes it', () => {
396
430
  const good = sanitizeHtml('<div data-embed-provider="youtube"><iframe src="https://www.youtube-nocookie.com/embed/abc123xyz"></iframe></div>');
397
431
  expect(good).to.include('youtube-nocookie.com/embed');
398
- const evil = sanitizeHtml('<iframe src="https://evil.example.com/steal"></iframe><p>ok</p>');
432
+ expect(good).to.include('sandbox=');
433
+ // A non-provider https iframe is kept, but sandboxed and cannot navigate the top.
434
+ const generic = sanitizeHtml('<iframe src="https://example.com/player"></iframe><p>ok</p>');
435
+ expect(generic).to.include('example.com/player');
436
+ expect(generic).to.include('sandbox=');
437
+ expect(generic).to.not.include('allow-top-navigation');
438
+ // Non-https iframes are still dropped entirely.
439
+ const evil = sanitizeHtml('<iframe src="http://evil.example.com/steal"></iframe><p>ok</p>');
399
440
  expect(evil).to.equal('<p>ok</p>');
400
441
  });
401
442
  it('round-trips embed nodes', () => {