@aquera/nile-elements 2.0.15 → 2.0.17
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.
- package/README.md +6 -0
- package/demo/nxtgen-classes.css +5 -5
- package/demo/nxtgen-dark.css +16 -16
- package/demo/nxtgen-properties.css +2 -2
- package/demo/nxtgen-utilities.css +5 -5
- package/demo/nxtgen.css +5 -5
- package/demo/utilities.css +2 -2
- package/demo/variables.css +2 -2
- package/dist/{index-f6944844.cjs.js → index-0c0c869d.cjs.js} +2 -2
- package/dist/{index-f6944844.cjs.js.map → index-0c0c869d.cjs.js.map} +1 -1
- package/dist/{index-403841c7.cjs.js → index-129ef6fb.cjs.js} +3 -3
- package/dist/{index-403841c7.cjs.js.map → index-129ef6fb.cjs.js.map} +1 -1
- package/dist/{index-1faa963c.esm.js → index-36f2a6b5.esm.js} +1 -1
- package/dist/index-4df50481.esm.js +1 -0
- package/dist/index-5d34cff1.esm.js +1 -0
- package/dist/index-7ae95edd.cjs.js +2 -0
- package/dist/{index-3ca67627.cjs.js.map → index-7ae95edd.cjs.js.map} +1 -1
- package/dist/index-7ca72b78.esm.js +1 -0
- package/dist/index-bbe23ad8.cjs.js +2 -0
- package/dist/index-bbe23ad8.cjs.js.map +1 -0
- package/dist/index-ccc6a799.cjs.js +5 -0
- package/dist/index-ccc6a799.cjs.js.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +124 -72
- package/dist/nile-auto-complete/index.cjs.js +1 -1
- package/dist/nile-auto-complete/nile-auto-complete.cjs.js +1 -1
- package/dist/nile-auto-complete/portal-manager.cjs.js +1 -1
- package/dist/nile-auto-complete/portal-utils.cjs.js +1 -1
- package/dist/nile-code-editor/extensionSetup.cjs.js +2 -2
- package/dist/nile-code-editor/index.cjs.js +1 -1
- package/dist/nile-code-editor/nile-code-editor.cjs.js +1 -1
- package/dist/nile-code-editor/theme.cjs.js +1 -1
- package/dist/nile-color-picker/index.cjs.js +1 -1
- package/dist/nile-color-picker/nile-color-picker.cjs.js +1 -1
- package/dist/nile-combobox/index.cjs.js +1 -1
- package/dist/nile-combobox/nile-combobox.cjs.js +1 -1
- package/dist/nile-combobox/portal-manager.cjs.js +1 -1
- package/dist/nile-context-menu/index.cjs.js +1 -1
- package/dist/nile-context-menu/nile-context-menu.cjs.js +1 -1
- package/dist/nile-context-submenu/index.cjs.js +1 -1
- package/dist/nile-context-submenu/nile-context-submenu.cjs.js +1 -1
- package/dist/nile-detail/index.cjs.js +1 -1
- package/dist/nile-detail/nile-detail.cjs.js +1 -1
- package/dist/nile-dropdown/index.cjs.js +1 -1
- package/dist/nile-dropdown/nile-dropdown.cjs.js +1 -1
- package/dist/nile-dropdown/portal-manager.cjs.js +1 -1
- package/dist/nile-file-upload/index.cjs.js +1 -1
- package/dist/nile-file-upload/nile-file-upload.cjs.js +1 -1
- package/dist/nile-file-upload/nile-file-upload.template.cjs.js +1 -1
- package/dist/nile-floating-panel/index.cjs.js +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.cjs.js +1 -1
- package/dist/nile-lite-tooltip/index.cjs.js +1 -1
- package/dist/nile-lite-tooltip/nile-lite-tooltip.cjs.js +1 -1
- package/dist/nile-lite-tooltip/nile-lite-tooltip.css.cjs.js +1 -1
- package/dist/nile-lite-tooltip/nile-lite-tooltip.css.cjs.js.map +1 -1
- package/dist/nile-lite-tooltip/nile-lite-tooltip.css.esm.js +1 -1
- package/dist/nile-markdown-editor/index.cjs.js +1 -1
- package/dist/nile-markdown-editor/nile-markdown-editor.cjs.js +1 -1
- package/dist/nile-popover/index.cjs.js +1 -1
- package/dist/nile-popover/nile-popover.cjs.js +1 -1
- package/dist/nile-popover/portal-manager.cjs.js +1 -1
- package/dist/nile-popup/index.cjs.js +1 -1
- package/dist/nile-popup/nile-popup.cjs.js +1 -1
- package/dist/nile-segmented-progress-bar/index.cjs.js +1 -1
- package/dist/nile-segmented-progress-bar/nile-segmented-progress-bar.cjs.js +1 -1
- package/dist/nile-select/index.cjs.js +1 -1
- package/dist/nile-select/nile-select.cjs.js +1 -1
- package/dist/nile-select/portal-manager.cjs.js +1 -1
- package/dist/nile-side-bar-action/index.cjs.js +1 -1
- package/dist/nile-side-bar-action/nile-side-bar-action.cjs.js +1 -1
- package/dist/nile-side-bar-action/portal-manager.cjs.js +1 -1
- package/dist/nile-tooltip/index.cjs.js +1 -1
- package/dist/nile-tooltip/nile-tooltip.cjs.js +1 -1
- package/dist/nile-tooltip/nile-tooltip.css.cjs.js +1 -1
- package/dist/nile-tooltip/nile-tooltip.css.cjs.js.map +1 -1
- package/dist/nile-tooltip/nile-tooltip.css.esm.js +1 -1
- package/dist/nile-virtual-select/index.cjs.js +1 -1
- package/dist/nile-virtual-select/nile-virtual-select.cjs.js +1 -1
- package/dist/nile-virtual-select/portal-manager.cjs.js +1 -1
- package/dist/nile-virtual-select/renderer.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/commands.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/commands.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/commands.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/create-state.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/create-state.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/create-state.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/email-css.cjs.js +2 -0
- package/dist/nile-wysiwyg-editor/engine/email-css.cjs.js.map +1 -0
- package/dist/nile-wysiwyg-editor/engine/email-css.esm.js +1 -0
- package/dist/nile-wysiwyg-editor/engine/email-render.cjs.js +2 -0
- package/dist/nile-wysiwyg-editor/engine/email-render.cjs.js.map +1 -0
- package/dist/nile-wysiwyg-editor/engine/email-render.esm.js +1 -0
- package/dist/nile-wysiwyg-editor/engine/html-detect.cjs.js +2 -0
- package/dist/nile-wysiwyg-editor/engine/html-detect.cjs.js.map +1 -0
- package/dist/nile-wysiwyg-editor/engine/html-detect.esm.js +1 -0
- package/dist/nile-wysiwyg-editor/engine/index.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/index.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/inputrules.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/inputrules.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/inputrules.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/keymap.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/keymap.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/keymap.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/code-highlight.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/embed-view.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/embeds.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/embeds.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/embeds.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/find-replace.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/find-replace.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/find-replace.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/format-painter.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/format-painter.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/format-painter.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/image-view.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/image-view.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/image-view.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/image.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/image.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/image.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/link.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/link.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/link.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/max-length.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/max-length.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/max-length.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/paste.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/paste.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/paste.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/placeholder.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/placeholder.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/placeholder.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/single-line.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/single-line.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/single-line.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/suggestions.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/suggestions.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/suggestions.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/tables.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/tables.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/plugins/tables.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/sanitize.cjs.js +2 -1
- package/dist/nile-wysiwyg-editor/engine/sanitize.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/sanitize.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/schema.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/schema.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/schema.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/selection-state.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/selection-state.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/selection-state.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/serializer.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/engine/serializer.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/engine/serializer.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/index.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/index.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.css.esm.js +45 -4
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.esm.js +2 -2
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/bookmark-panel.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/bookmark-panel.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/bookmark-panel.esm.js +2 -2
- package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/bubble-menu.esm.js +5 -5
- package/dist/nile-wysiwyg-editor/ui/code-block-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/code-block-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/code-block-menu.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-menu.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-panel.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-panel.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-panel.esm.js +2 -2
- package/dist/nile-wysiwyg-editor/ui/emoji-picker.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/emoji-picker.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/emoji-picker.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/find-replace.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/find-replace.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/find-replace.esm.js +3 -3
- package/dist/nile-wysiwyg-editor/ui/image-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/image-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/image-menu.esm.js +3 -3
- package/dist/nile-wysiwyg-editor/ui/image-panel.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/image-panel.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/image-panel.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/insert-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/insert-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/insert-menu.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/link-editor.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/link-editor.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/link-editor.esm.js +9 -9
- package/dist/nile-wysiwyg-editor/ui/markdown-panel.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/markdown-panel.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/markdown-panel.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/math-panel.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/math-panel.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/math-panel.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/shortcut-help.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/shortcut-help.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/shortcut-help.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/source-view.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/source-view.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/source-view.esm.js +4 -4
- package/dist/nile-wysiwyg-editor/ui/special-chars.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/special-chars.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/special-chars.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/suggest-list.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/suggest-list.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/suggest-list.esm.js +23 -12
- package/dist/nile-wysiwyg-editor/ui/table-grid-picker.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/table-grid-picker.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/table-grid-picker.esm.js +7 -7
- package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/table-menu.esm.js +1 -1
- package/dist/src/nile-lite-tooltip/nile-lite-tooltip.css.js +1 -1
- package/dist/src/nile-lite-tooltip/nile-lite-tooltip.css.js.map +1 -1
- package/dist/src/nile-tooltip/nile-tooltip.css.js +1 -1
- package/dist/src/nile-tooltip/nile-tooltip.css.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/create-state.d.ts +5 -0
- package/dist/src/nile-wysiwyg-editor/engine/create-state.js +2 -0
- package/dist/src/nile-wysiwyg-editor/engine/create-state.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/email-css.d.ts +14 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-css.js +140 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-css.js.map +1 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-fidelity.test.d.ts +1 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-fidelity.test.js +1045 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-fidelity.test.js.map +1 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-render.d.ts +11 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-render.js +93 -0
- package/dist/src/nile-wysiwyg-editor/engine/email-render.js.map +1 -0
- package/dist/src/nile-wysiwyg-editor/engine/html-detect.d.ts +2 -0
- package/dist/src/nile-wysiwyg-editor/engine/html-detect.js +24 -0
- package/dist/src/nile-wysiwyg-editor/engine/html-detect.js.map +1 -0
- package/dist/src/nile-wysiwyg-editor/engine/index.d.ts +4 -1
- package/dist/src/nile-wysiwyg-editor/engine/index.js +3 -1
- package/dist/src/nile-wysiwyg-editor/engine/index.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/inputrules.d.ts +0 -5
- package/dist/src/nile-wysiwyg-editor/engine/inputrules.js +19 -0
- package/dist/src/nile-wysiwyg-editor/engine/inputrules.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/plugins/image-view.js +3 -2
- package/dist/src/nile-wysiwyg-editor/engine/plugins/image-view.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/plugins/link.d.ts +4 -0
- package/dist/src/nile-wysiwyg-editor/engine/plugins/link.js +56 -1
- package/dist/src/nile-wysiwyg-editor/engine/plugins/link.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/plugins/paste.d.ts +5 -0
- package/dist/src/nile-wysiwyg-editor/engine/plugins/paste.js +27 -6
- package/dist/src/nile-wysiwyg-editor/engine/plugins/paste.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/plugins/tables.js +30 -7
- package/dist/src/nile-wysiwyg-editor/engine/plugins/tables.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/pm.test.js +46 -0
- package/dist/src/nile-wysiwyg-editor/engine/pm.test.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/sanitize.d.ts +9 -1
- package/dist/src/nile-wysiwyg-editor/engine/sanitize.js +730 -7
- package/dist/src/nile-wysiwyg-editor/engine/sanitize.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/schema.d.ts +3 -0
- package/dist/src/nile-wysiwyg-editor/engine/schema.js +215 -34
- package/dist/src/nile-wysiwyg-editor/engine/schema.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/selection-state.js +3 -1
- package/dist/src/nile-wysiwyg-editor/engine/selection-state.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/engine/serializer.d.ts +12 -4
- package/dist/src/nile-wysiwyg-editor/engine/serializer.js +18 -8
- package/dist/src/nile-wysiwyg-editor/engine/serializer.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.d.ts +1 -0
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.js +287 -0
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.js.map +1 -0
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.js +45 -4
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.d.ts +23 -0
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.js +113 -15
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.js +213 -0
- package/dist/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/bookmark-panel.js +2 -2
- package/dist/src/nile-wysiwyg-editor/ui/bookmark-panel.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/bubble-menu.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/embed-menu.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/embed-menu.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/embed-panel.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/embed-panel.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/emoji-picker.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/emoji-picker.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/find-replace.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/find-replace.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/image-menu.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/image-menu.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/image-panel.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/image-panel.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/insert-menu.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/insert-menu.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/link-editor.js +2 -2
- package/dist/src/nile-wysiwyg-editor/ui/link-editor.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/markdown-panel.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/markdown-panel.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/math-panel.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/math-panel.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/shortcut-help.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/shortcut-help.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/source-view.js +2 -2
- package/dist/src/nile-wysiwyg-editor/ui/source-view.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/special-chars.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/special-chars.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/suggest-list.js +14 -3
- package/dist/src/nile-wysiwyg-editor/ui/suggest-list.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.js +2 -2
- package/dist/src/nile-wysiwyg-editor/ui/table-grid-picker.js.map +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/table-menu.js +1 -1
- package/dist/src/nile-wysiwyg-editor/ui/table-menu.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.cjs.js +1 -1
- package/dist/version.cjs.js.map +1 -1
- package/dist/version.esm.js +1 -1
- package/package.json +1 -1
- package/src/nile-lite-tooltip/nile-lite-tooltip.css.ts +1 -1
- package/src/nile-tooltip/nile-tooltip.css.ts +1 -1
- package/src/nile-wysiwyg-editor/engine/create-state.ts +7 -0
- package/src/nile-wysiwyg-editor/engine/email-css.ts +136 -0
- package/src/nile-wysiwyg-editor/engine/email-fidelity.test.ts +1347 -0
- package/src/nile-wysiwyg-editor/engine/email-render.ts +99 -0
- package/src/nile-wysiwyg-editor/engine/html-detect.ts +26 -0
- package/src/nile-wysiwyg-editor/engine/index.ts +10 -1
- package/src/nile-wysiwyg-editor/engine/inputrules.ts +18 -1
- package/src/nile-wysiwyg-editor/engine/plugins/image-view.ts +3 -2
- package/src/nile-wysiwyg-editor/engine/plugins/link.ts +58 -2
- package/src/nile-wysiwyg-editor/engine/plugins/paste.ts +31 -8
- package/src/nile-wysiwyg-editor/engine/plugins/tables.ts +29 -7
- package/src/nile-wysiwyg-editor/engine/pm.test.ts +73 -0
- package/src/nile-wysiwyg-editor/engine/sanitize.ts +729 -7
- package/src/nile-wysiwyg-editor/engine/schema.ts +206 -33
- package/src/nile-wysiwyg-editor/engine/selection-state.ts +3 -1
- package/src/nile-wysiwyg-editor/engine/serializer.ts +30 -8
- package/src/nile-wysiwyg-editor/nile-wysiwyg-editor-email-fidelity.test.ts +357 -0
- package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.css.ts +45 -4
- package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.test.ts +258 -0
- package/src/nile-wysiwyg-editor/nile-wysiwyg-editor.ts +119 -12
- package/src/nile-wysiwyg-editor/ui/bookmark-panel.ts +2 -2
- package/src/nile-wysiwyg-editor/ui/bubble-menu.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/embed-menu.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/embed-panel.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/emoji-picker.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/find-replace.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/image-menu.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/image-panel.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/insert-menu.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/link-editor.ts +2 -2
- package/src/nile-wysiwyg-editor/ui/markdown-panel.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/math-panel.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/shortcut-help.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/source-view.ts +2 -2
- package/src/nile-wysiwyg-editor/ui/special-chars.ts +1 -1
- package/src/nile-wysiwyg-editor/ui/suggest-list.ts +14 -3
- package/src/nile-wysiwyg-editor/ui/table-grid-picker.ts +2 -2
- package/src/nile-wysiwyg-editor/ui/table-menu.ts +1 -1
- package/vscode-html-custom-data.json +15 -1
- package/web-test-runner.config.mjs +4 -0
- package/dist/index-3ca67627.cjs.js +0 -2
- package/dist/index-6f3fa4ab.esm.js +0 -1
- package/dist/index-7b1c9857.esm.js +0 -1
- package/dist/index-89c520e9.cjs.js +0 -5
- package/dist/index-89c520e9.cjs.js.map +0 -1
- package/dist/index-ba47645d.esm.js +0 -1
- package/dist/index-c3210a9c.cjs.js +0 -2
- 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
|
-
/**
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
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: {
|
|
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
|
-
|
|
699
|
-
|
|
700
|
-
:
|
|
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(
|
|
33
|
-
|
|
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(
|
|
40
|
-
|
|
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
|
|
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(
|
|
70
|
+
container.appendChild(getSerializer(schema).serializeFragment(source.content));
|
|
71
|
+
if (emailDefaults) finishEmailTables(container);
|
|
50
72
|
return container.innerHTML;
|
|
51
73
|
}
|
|
52
74
|
|