@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.
- package/README.md +6 -0
- 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 +686 -464
- 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-markdown-editor/index.cjs.js +1 -1
- package/dist/nile-markdown-editor/nile-markdown-editor.cjs.js +1 -1
- package/dist/nile-minimap/index.cjs.js +2 -0
- package/dist/nile-minimap/index.cjs.js.map +1 -0
- package/dist/nile-minimap/index.esm.js +1 -0
- package/dist/nile-minimap/nile-minimap.cjs.js +2 -0
- package/dist/nile-minimap/nile-minimap.cjs.js.map +1 -0
- package/dist/nile-minimap/nile-minimap.css.cjs.js +2 -0
- package/dist/nile-minimap/nile-minimap.css.cjs.js.map +1 -0
- package/dist/nile-minimap/nile-minimap.css.esm.js +150 -0
- package/dist/nile-minimap/nile-minimap.esm.js +22 -0
- 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-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/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/nile-minimap/index.d.ts +1 -0
- package/dist/src/nile-minimap/index.js +2 -0
- package/dist/src/nile-minimap/index.js.map +1 -0
- package/dist/src/nile-minimap/nile-minimap.css.d.ts +12 -0
- package/dist/src/nile-minimap/nile-minimap.css.js +162 -0
- package/dist/src/nile-minimap/nile-minimap.css.js.map +1 -0
- package/dist/src/nile-minimap/nile-minimap.d.ts +131 -0
- package/dist/src/nile-minimap/nile-minimap.js +704 -0
- package/dist/src/nile-minimap/nile-minimap.js.map +1 -0
- package/dist/src/nile-minimap/nile-minimap.test.d.ts +1 -0
- package/dist/src/nile-minimap/nile-minimap.test.js +785 -0
- package/dist/src/nile-minimap/nile-minimap.test.js.map +1 -0
- 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/package.json +2 -1
- package/src/index.ts +1 -0
- package/src/nile-minimap/index.ts +1 -0
- package/src/nile-minimap/nile-minimap.css.ts +164 -0
- package/src/nile-minimap/nile-minimap.test.ts +924 -0
- package/src/nile-minimap/nile-minimap.ts +796 -0
- 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 +116 -25
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inputrules.js","sourceRoot":"","sources":["../../../../src/nile-wysiwyg-editor/engine/inputrules.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n inputRules,\n wrappingInputRule,\n textblockTypeInputRule,\n InputRule,\n} from 'prosemirror-inputrules';\nimport { MarkType, Schema } from 'prosemirror-model';\nimport { Plugin } from 'prosemirror-state';\n\nfunction escapeRegex(text: string): string {\n return text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** True when the cursor sits in code (block or mark) — no autocorrect there. */\nfunction isInCodeContext(state: import('prosemirror-state').EditorState): boolean {\n const { $from } = state.selection;\n if ($from.parent.type.spec.code) return true;\n const code = state.schema.marks.code;\n return !!(code && code.isInSet(state.storedMarks || $from.marks()));\n}\n\n/**\n * String-replacement rule (the library stringHandler plus a code-context\n * guard): when the regex has a capture group, only the group is replaced and\n * the surrounding matched text is preserved.\n */\nfunction replaceRule(regexp: RegExp, replacement: string): InputRule {\n return new InputRule(regexp, (state, match, start, end) => {\n if (isInCodeContext(state)) return null;\n let insert = replacement;\n let from = start;\n if (match.length > 1 && match[1] !== undefined) {\n const offset = match[0].lastIndexOf(match[1]);\n insert += match[0].slice(offset + match[1].length);\n from += offset;\n const cutOff = from - end;\n if (cutOff > 0) {\n insert = match[0].slice(offset - cutOff, offset) + insert;\n from = end;\n }\n }\n return state.tr.insertText(insert, from, end);\n });\n}\n\n/**\n * CKEditor-style text transformations: symbols, fractions, dashes, ellipsis\n * and smart quotes. All skipped inside code and revertable with Backspace.\n */\nfunction textTransformRules(): InputRule[] {\n return [\n // Symbols.\n replaceRule(/\\(c\\)$/i, '©'),\n replaceRule(/\\(r\\)$/i, '®'),\n replaceRule(/\\(tm\\)$/i, '™'),\n // Fractions (word-bounded, completed by a space).\n replaceRule(/(?:^|\\s)(1\\/2)\\s$/, '½'),\n replaceRule(/(?:^|\\s)(1\\/4)\\s$/, '¼'),\n replaceRule(/(?:^|\\s)(3\\/4)\\s$/, '¾'),\n // Dashes: \" --- \" → em, \" -- \" → en. The em rule can't be shadowed by\n // the en rule because the en rule requires whitespace before \"--\".\n replaceRule(/\\s(---)\\s$/, '—'),\n replaceRule(/\\s(--)\\s$/, '–'),\n // Ellipsis.\n replaceRule(/\\.\\.\\.$/, '…'),\n // Smart quotes: opening after start/space/bracket, closing elsewhere.\n replaceRule(/(?:^|[\\s{[(<'\"‘“])(\")$/, '“'),\n replaceRule(/\"$/, '”'),\n replaceRule(/(?:^|[\\s{[(<'\"‘“])(')$/, '‘'),\n replaceRule(/'$/, '’'),\n ];\n}\n\nexport interface InputRulesOptions {\n /** Include the autocorrect/typography rules. Defaults to true. */\n textTransform?: boolean;\n}\n\n/**\n * Markdown mark shortcut: typing `<delim>text<delim>` applies the mark and\n * strips the delimiters. The matched range (delimiters and all) is replaced\n * with the marked content, so the final typed delimiter never lands.\n */\nfunction markInputRule(delim: string, markType: MarkType): InputRule {\n const escaped = escapeRegex(delim);\n const inner = escapeRegex(delim[0]);\n const regexp = new RegExp(\n `(?:^|\\\\s)${escaped}([^${inner}\\\\s](?:[^${inner}]*[^${inner}\\\\s])?)${escaped}$`\n );\n return new InputRule(regexp, (state, match, start, end) => {\n const content = match[1];\n const delimStart = start + match[0].indexOf(delim);\n const tr = state.tr;\n tr.delete(delimStart, end);\n tr.insertText(content, delimStart);\n tr.addMark(delimStart, delimStart + content.length, markType.create());\n tr.removeStoredMark(markType);\n return tr;\n });\n}\n\n/**\n * Autolink: typing a space after a bare URL (`https://…`, `http://…` or\n * `www.…`) converts it into a link. Trailing punctuation stays outside the\n * link, code spans and existing links are left alone, and Backspace\n * (undoInputRule) reverts the conversion like any other input rule.\n */\nfunction linkifyRule(schema: Schema): InputRule {\n const linkType = schema.marks.link;\n const regexp = /(?:^|\\s)((?:https?:\\/\\/|www\\.)[^\\s]*[^\\s.,:;!?'\")\\]}])\\s$/i;\n return new InputRule(regexp, (state, match, start, end) => {\n const url = match[1];\n const urlStart = start + match[0].indexOf(url);\n const urlEnd = urlStart + url.length;\n if (state.doc.rangeHasMark(urlStart, urlEnd, linkType)) return null;\n if (state.doc.rangeHasMark(urlStart, urlEnd, schema.marks.code)) return null;\n const href = /^www\\./i.test(url) ? `https://${url}` : url;\n const tr = state.tr;\n tr.addMark(urlStart, urlEnd, linkType.create({ href }));\n tr.removeStoredMark(linkType);\n tr.insertText(' ', end);\n return tr;\n });\n}\n\n/**\n * Markdown-style typing shortcuts: block rules plus inline mark rules\n * (**bold**, *italic*, `code`, ~~strike~~), and (unless disabled) the\n * typography autocorrect rules.\n */\nexport function buildInputRules(schema: Schema, options: InputRulesOptions = {}): Plugin {\n const transforms = options.textTransform === false ? [] : textTransformRules();\n return inputRules({\n rules: [\n ...transforms,\n // \"# \" … \"###### \" → heading\n textblockTypeInputRule(\n new RegExp('^(#{1,6})\\\\s$'),\n schema.nodes.heading,\n match => ({ level: match[1].length })\n ),\n // \"> \" → blockquote\n wrappingInputRule(/^\\s*>\\s$/, schema.nodes.blockquote),\n // \"- \" or \"* \" → bullet list\n wrappingInputRule(/^\\s*([-*])\\s$/, schema.nodes.bullet_list),\n // \"1. \" → ordered list\n wrappingInputRule(\n /^(\\d+)\\.\\s$/,\n schema.nodes.ordered_list,\n match => ({ order: +match[1] }),\n (match, node) => node.childCount + node.attrs.order === +match[1]\n ),\n // \"```\" → code block\n textblockTypeInputRule(/^```$/, schema.nodes.code_block),\n // \"[] \" or \"[ ] \" → checklist\n wrappingInputRule(/^\\s*\\[[ ]?\\]\\s$/, schema.nodes.task_list),\n // Inline marks. Bold before italic so '**' is never read as italic;\n // strike (~~) before subscript (~) so a double tilde is never a single.\n markInputRule('**', schema.marks.bold),\n markInputRule('*', schema.marks.italic),\n markInputRule('~~', schema.marks.strike),\n markInputRule('~', schema.marks.subscript),\n markInputRule('^', schema.marks.superscript),\n markInputRule('`', schema.marks.code),\n // Bare URL + space → link.\n linkifyRule(schema),\n ],\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"inputrules.js","sourceRoot":"","sources":["../../../../src/nile-wysiwyg-editor/engine/inputrules.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,SAAS,GACV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAU,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE1D,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,gFAAgF;AAChF,SAAS,eAAe,CAAC,KAA8C;IACrE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IACrC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,MAAc,EAAE,WAAmB;IACtD,OAAO,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACxD,IAAI,eAAe,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,MAAM,GAAG,WAAW,CAAC;QACzB,IAAI,IAAI,GAAG,KAAK,CAAC;QACjB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACnD,IAAI,IAAI,MAAM,CAAC;YACf,MAAM,MAAM,GAAG,IAAI,GAAG,GAAG,CAAC;YAC1B,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACf,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC;gBAC1D,IAAI,GAAG,GAAG,CAAC;YACb,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,kBAAkB;IACzB,OAAO;QACL,WAAW;QACX,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC;QAC3B,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC;QAC3B,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC;QAC5B,kDAAkD;QAClD,WAAW,CAAC,mBAAmB,EAAE,GAAG,CAAC;QACrC,WAAW,CAAC,mBAAmB,EAAE,GAAG,CAAC;QACrC,WAAW,CAAC,mBAAmB,EAAE,GAAG,CAAC;QACrC,sEAAsE;QACtE,mEAAmE;QACnE,WAAW,CAAC,YAAY,EAAE,GAAG,CAAC;QAC9B,WAAW,CAAC,WAAW,EAAE,GAAG,CAAC;QAC7B,YAAY;QACZ,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC;QAC3B,sEAAsE;QACtE,WAAW,CAAC,wBAAwB,EAAE,GAAG,CAAC;QAC1C,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC;QACtB,WAAW,CAAC,wBAAwB,EAAE,GAAG,CAAC;QAC1C,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC;KACvB,CAAC;AACJ,CAAC;AAOD;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAa,EAAE,QAAkB;IACtD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,YAAY,OAAO,MAAM,KAAK,YAAY,KAAK,OAAO,KAAK,UAAU,OAAO,GAAG,CAChF,CAAC;IACF,OAAO,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACxD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;QACpB,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC3B,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACnC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACvE,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,4DAA4D,CAAC;IAC5E,OAAO,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACxD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC;QACrC,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACpE,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7E,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1D,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;QACpB,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACxD,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,8EAA8E;AAC9E,SAAS,kBAAkB,CAAC,MAAc;IACxC,OAAO,IAAI,SAAS,CAAC,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;QACpE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;QACxD,iEAAiE;QACjE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACtF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QACvE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3F,OAAO,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,UAA6B,EAAE;IAC7E,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAC/E,OAAO,UAAU,CAAC;QAChB,KAAK,EAAE;YACL,GAAG,UAAU;YACb,6BAA6B;YAC7B,sBAAsB,CACpB,IAAI,MAAM,CAAC,eAAe,CAAC,EAC3B,MAAM,CAAC,KAAK,CAAC,OAAO,EACpB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CACtC;YACD,oBAAoB;YACpB,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;YACtD,6BAA6B;YAC7B,iBAAiB,CAAC,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC;YAC5D,uBAAuB;YACvB,iBAAiB,CACf,aAAa,EACb,MAAM,CAAC,KAAK,CAAC,YAAY,EACzB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAC/B,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAClE;YACD,qBAAqB;YACrB,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;YACxD,0CAA0C;YAC1C,kBAAkB,CAAC,MAAM,CAAC;YAC1B,8BAA8B;YAC9B,iBAAiB,CAAC,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;YAC5D,oEAAoE;YACpE,wEAAwE;YACxE,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACtC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;YACvC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;YACxC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;YAC1C,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC;YAC5C,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACrC,2BAA2B;YAC3B,WAAW,CAAC,MAAM,CAAC;SACpB;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import {\n inputRules,\n wrappingInputRule,\n textblockTypeInputRule,\n InputRule,\n} from 'prosemirror-inputrules';\nimport { MarkType, Schema } from 'prosemirror-model';\nimport { Plugin, TextSelection } from 'prosemirror-state';\n\nfunction escapeRegex(text: string): string {\n return text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** True when the cursor sits in code (block or mark) — no autocorrect there. */\nfunction isInCodeContext(state: import('prosemirror-state').EditorState): boolean {\n const { $from } = state.selection;\n if ($from.parent.type.spec.code) return true;\n const code = state.schema.marks.code;\n return !!(code && code.isInSet(state.storedMarks || $from.marks()));\n}\n\n/**\n * String-replacement rule (the library stringHandler plus a code-context\n * guard): when the regex has a capture group, only the group is replaced and\n * the surrounding matched text is preserved.\n */\nfunction replaceRule(regexp: RegExp, replacement: string): InputRule {\n return new InputRule(regexp, (state, match, start, end) => {\n if (isInCodeContext(state)) return null;\n let insert = replacement;\n let from = start;\n if (match.length > 1 && match[1] !== undefined) {\n const offset = match[0].lastIndexOf(match[1]);\n insert += match[0].slice(offset + match[1].length);\n from += offset;\n const cutOff = from - end;\n if (cutOff > 0) {\n insert = match[0].slice(offset - cutOff, offset) + insert;\n from = end;\n }\n }\n return state.tr.insertText(insert, from, end);\n });\n}\n\n/**\n * CKEditor-style text transformations: symbols, fractions, dashes, ellipsis\n * and smart quotes. All skipped inside code and revertable with Backspace.\n */\nfunction textTransformRules(): InputRule[] {\n return [\n // Symbols.\n replaceRule(/\\(c\\)$/i, '©'),\n replaceRule(/\\(r\\)$/i, '®'),\n replaceRule(/\\(tm\\)$/i, '™'),\n // Fractions (word-bounded, completed by a space).\n replaceRule(/(?:^|\\s)(1\\/2)\\s$/, '½'),\n replaceRule(/(?:^|\\s)(1\\/4)\\s$/, '¼'),\n replaceRule(/(?:^|\\s)(3\\/4)\\s$/, '¾'),\n // Dashes: \" --- \" → em, \" -- \" → en. The em rule can't be shadowed by\n // the en rule because the en rule requires whitespace before \"--\".\n replaceRule(/\\s(---)\\s$/, '—'),\n replaceRule(/\\s(--)\\s$/, '–'),\n // Ellipsis.\n replaceRule(/\\.\\.\\.$/, '…'),\n // Smart quotes: opening after start/space/bracket, closing elsewhere.\n replaceRule(/(?:^|[\\s{[(<'\"‘“])(\")$/, '“'),\n replaceRule(/\"$/, '”'),\n replaceRule(/(?:^|[\\s{[(<'\"‘“])(')$/, '‘'),\n replaceRule(/'$/, '’'),\n ];\n}\n\nexport interface InputRulesOptions {\n /** Include the autocorrect/typography rules. Defaults to true. */\n textTransform?: boolean;\n}\n\n/**\n * Markdown mark shortcut: typing `<delim>text<delim>` applies the mark and\n * strips the delimiters. The matched range (delimiters and all) is replaced\n * with the marked content, so the final typed delimiter never lands.\n */\nfunction markInputRule(delim: string, markType: MarkType): InputRule {\n const escaped = escapeRegex(delim);\n const inner = escapeRegex(delim[0]);\n const regexp = new RegExp(\n `(?:^|\\\\s)${escaped}([^${inner}\\\\s](?:[^${inner}]*[^${inner}\\\\s])?)${escaped}$`\n );\n return new InputRule(regexp, (state, match, start, end) => {\n const content = match[1];\n const delimStart = start + match[0].indexOf(delim);\n const tr = state.tr;\n tr.delete(delimStart, end);\n tr.insertText(content, delimStart);\n tr.addMark(delimStart, delimStart + content.length, markType.create());\n tr.removeStoredMark(markType);\n return tr;\n });\n}\n\n/**\n * Autolink: typing a space after a bare URL (`https://…`, `http://…` or\n * `www.…`) converts it into a link. Trailing punctuation stays outside the\n * link, code spans and existing links are left alone, and Backspace\n * (undoInputRule) reverts the conversion like any other input rule.\n */\nfunction linkifyRule(schema: Schema): InputRule {\n const linkType = schema.marks.link;\n const regexp = /(?:^|\\s)((?:https?:\\/\\/|www\\.)[^\\s]*[^\\s.,:;!?'\")\\]}])\\s$/i;\n return new InputRule(regexp, (state, match, start, end) => {\n const url = match[1];\n const urlStart = start + match[0].indexOf(url);\n const urlEnd = urlStart + url.length;\n if (state.doc.rangeHasMark(urlStart, urlEnd, linkType)) return null;\n if (state.doc.rangeHasMark(urlStart, urlEnd, schema.marks.code)) return null;\n const href = /^www\\./i.test(url) ? `https://${url}` : url;\n const tr = state.tr;\n tr.addMark(urlStart, urlEnd, linkType.create({ href }));\n tr.removeStoredMark(linkType);\n tr.insertText(' ', end);\n return tr;\n });\n}\n\n/**\n * Markdown-style typing shortcuts: block rules plus inline mark rules\n * (**bold**, *italic*, `code`, ~~strike~~), and (unless disabled) the\n * typography autocorrect rules.\n */\n/** \"---\", \"***\" or \"___\" alone in a top-level paragraph → horizontal rule. */\nfunction horizontalRuleRule(schema: Schema): InputRule {\n return new InputRule(/^(?:---|\\*\\*\\*|___)$/, (state, _match, start) => {\n const $start = state.doc.resolve(start);\n const { paragraph, horizontal_rule: hr } = schema.nodes;\n // The rule's two earlier characters must be the whole paragraph.\n if ($start.parent.type !== paragraph || $start.parent.content.size !== 2) return null;\n const index = $start.index(-1);\n if (!$start.node(-1).canReplaceWith(index, index + 1, hr)) return null;\n const before = $start.before();\n const tr = state.tr.replaceWith(before, $start.after(), [hr.create(), paragraph.create()]);\n return tr.setSelection(TextSelection.create(tr.doc, before + 2)).scrollIntoView();\n });\n}\n\nexport function buildInputRules(schema: Schema, options: InputRulesOptions = {}): Plugin {\n const transforms = options.textTransform === false ? [] : textTransformRules();\n return inputRules({\n rules: [\n ...transforms,\n // \"# \" … \"###### \" → heading\n textblockTypeInputRule(\n new RegExp('^(#{1,6})\\\\s$'),\n schema.nodes.heading,\n match => ({ level: match[1].length })\n ),\n // \"> \" → blockquote\n wrappingInputRule(/^\\s*>\\s$/, schema.nodes.blockquote),\n // \"- \" or \"* \" → bullet list\n wrappingInputRule(/^\\s*([-*])\\s$/, schema.nodes.bullet_list),\n // \"1. \" → ordered list\n wrappingInputRule(\n /^(\\d+)\\.\\s$/,\n schema.nodes.ordered_list,\n match => ({ order: +match[1] }),\n (match, node) => node.childCount + node.attrs.order === +match[1]\n ),\n // \"```\" → code block\n textblockTypeInputRule(/^```$/, schema.nodes.code_block),\n // \"---\" / \"***\" / \"___\" → horizontal rule\n horizontalRuleRule(schema),\n // \"[] \" or \"[ ] \" → checklist\n wrappingInputRule(/^\\s*\\[[ ]?\\]\\s$/, schema.nodes.task_list),\n // Inline marks. Bold before italic so '**' is never read as italic;\n // strike (~~) before subscript (~) so a double tilde is never a single.\n markInputRule('**', schema.marks.bold),\n markInputRule('*', schema.marks.italic),\n markInputRule('~~', schema.marks.strike),\n markInputRule('~', schema.marks.subscript),\n markInputRule('^', schema.marks.superscript),\n markInputRule('`', schema.marks.code),\n // Bare URL + space → link.\n linkifyRule(schema),\n ],\n });\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NodeSelection } from 'prosemirror-state';
|
|
2
|
+
import { imageWidthCss } from '../schema';
|
|
2
3
|
const MIN_WIDTH = 40;
|
|
3
4
|
/**
|
|
4
5
|
* Attaches four corner drag-handles to a wrapper and returns a cleanup
|
|
@@ -71,7 +72,7 @@ export class ImageView {
|
|
|
71
72
|
this.img.title = title;
|
|
72
73
|
else
|
|
73
74
|
this.img.removeAttribute('title');
|
|
74
|
-
this.img.style.width = width
|
|
75
|
+
this.img.style.width = imageWidthCss(width) ?? '';
|
|
75
76
|
}
|
|
76
77
|
update(node) {
|
|
77
78
|
if (node.type !== this.node.type)
|
|
@@ -143,7 +144,7 @@ export class FigureView {
|
|
|
143
144
|
this.img.title = title;
|
|
144
145
|
else
|
|
145
146
|
this.img.removeAttribute('title');
|
|
146
|
-
this.dom.style.width = width
|
|
147
|
+
this.dom.style.width = imageWidthCss(width) ?? '';
|
|
147
148
|
if (align)
|
|
148
149
|
this.dom.setAttribute('data-align', align);
|
|
149
150
|
else
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-view.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/image-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { Node as PMNode } from 'prosemirror-model';\nimport { EditorView, NodeView } from 'prosemirror-view';\nimport { NodeSelection } from 'prosemirror-state';\n\nconst MIN_WIDTH = 40;\n\n/**\n * Attaches four corner drag-handles to a wrapper and returns a cleanup\n * function. Dragging previews by mutating the target's style; on release the\n * final width is committed through onCommit (one transaction).\n */\nexport function attachResizeHandles(\n wrapper: HTMLElement,\n img: HTMLElement,\n onCommit: (width: number) => void,\n minWidth: number = MIN_WIDTH\n): void {\n for (const corner of ['nw', 'ne', 'sw', 'se']) {\n const handle = document.createElement('span');\n handle.className = `nile-wysiwyg__resize-handle nile-wysiwyg__resize-handle--${corner}`;\n handle.dataset.resizeHandle = corner;\n handle.contentEditable = 'false';\n handle.addEventListener('mousedown', event => {\n event.preventDefault();\n event.stopPropagation();\n const startX = event.clientX;\n const startWidth = img.getBoundingClientRect().width;\n const sign = corner.includes('w') ? -1 : 1;\n const maxWidth =\n wrapper.closest('.ProseMirror')?.getBoundingClientRect().width ?? 2000;\n let width = startWidth;\n const onMove = (move: MouseEvent): void => {\n width = Math.max(\n minWidth,\n Math.min(maxWidth, startWidth + sign * (move.clientX - startX))\n );\n img.style.width = `${Math.round(width)}px`;\n };\n const onUp = (): void => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n wrapper.classList.remove('nile-wysiwyg__resizing');\n onCommit(Math.round(width));\n };\n // While dragging, iframes inside the wrapper must not swallow mouse\n // events (they are separate documents); CSS keys off this class.\n wrapper.classList.add('nile-wysiwyg__resizing');\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n });\n wrapper.appendChild(handle);\n }\n}\n\nexport function isResizeEvent(event: Event): boolean {\n return (\n event.target instanceof HTMLElement && !!event.target.dataset.resizeHandle\n );\n}\n\n/** Inline image with drag-resize handles shown while selected. */\nexport class ImageView implements NodeView {\n dom: HTMLSpanElement;\n\n private img: HTMLImageElement;\n\n constructor(\n private node: PMNode,\n view: EditorView,\n getPos: () => number | undefined\n ) {\n this.dom = document.createElement('span');\n this.dom.className = 'nile-wysiwyg__image-resizer';\n this.img = document.createElement('img');\n this.applyAttrs(node);\n this.dom.appendChild(this.img);\n attachResizeHandles(this.dom, this.img, width => {\n const pos = getPos();\n if (pos === undefined || !view.editable) return;\n const current = view.state.doc.nodeAt(pos);\n if (!current) return;\n view.dispatch(\n view.state.tr.setNodeMarkup(pos, undefined, { ...current.attrs, width })\n );\n });\n }\n\n private applyAttrs(node: PMNode): void {\n const { src, alt, title, width } = node.attrs;\n this.img.src = src;\n if (alt) this.img.alt = alt;\n else this.img.removeAttribute('alt');\n if (title) this.img.title = title;\n else this.img.removeAttribute('title');\n this.img.style.width = width ? `${width}px` : '';\n }\n\n update(node: PMNode): boolean {\n if (node.type !== this.node.type) return false;\n this.node = node;\n this.applyAttrs(node);\n return true;\n }\n\n selectNode(): void {\n this.dom.classList.add('nile-wysiwyg__image-resizer--selected');\n }\n\n deselectNode(): void {\n this.dom.classList.remove('nile-wysiwyg__image-resizer--selected');\n }\n\n stopEvent(event: Event): boolean {\n return isResizeEvent(event);\n }\n\n ignoreMutation(): boolean {\n return true;\n }\n}\n\n/**\n * Captioned figure: non-editable image (with resize handles) above an\n * editable figcaption (the node's content). Clicking the image selects the\n * whole figure.\n */\nexport class FigureView implements NodeView {\n dom: HTMLElement;\n\n contentDOM: HTMLElement;\n\n private img: HTMLImageElement;\n\n private wrapper: HTMLSpanElement;\n\n constructor(\n private node: PMNode,\n view: EditorView,\n getPos: () => number | undefined\n ) {\n this.dom = document.createElement('figure');\n this.dom.className = 'nile-wysiwyg__figure';\n\n this.wrapper = document.createElement('span');\n this.wrapper.className = 'nile-wysiwyg__image-resizer';\n this.wrapper.contentEditable = 'false';\n this.img = document.createElement('img');\n this.wrapper.appendChild(this.img);\n\n this.contentDOM = document.createElement('figcaption');\n this.contentDOM.className = 'nile-wysiwyg__figcaption';\n\n this.dom.append(this.wrapper, this.contentDOM);\n this.applyAttrs(node);\n\n // Clicking the image selects the figure node (instead of dropping the\n // cursor into the caption).\n this.img.addEventListener('mousedown', event => {\n event.preventDefault();\n const pos = getPos();\n if (pos === undefined) return;\n view.dispatch(\n view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos))\n );\n view.focus();\n });\n\n attachResizeHandles(this.wrapper, this.img, width => {\n const pos = getPos();\n if (pos === undefined || !view.editable) return;\n const current = view.state.doc.nodeAt(pos);\n if (!current) return;\n view.dispatch(\n view.state.tr.setNodeMarkup(pos, undefined, { ...current.attrs, width })\n );\n });\n }\n\n private applyAttrs(node: PMNode): void {\n const { src, alt, title, width, align } = node.attrs;\n this.img.src = src;\n if (alt) this.img.alt = alt;\n else this.img.removeAttribute('alt');\n if (title) this.img.title = title;\n else this.img.removeAttribute('title');\n this.dom.style.width = width ? `${width}px` : '';\n if (align) this.dom.setAttribute('data-align', align);\n else this.dom.removeAttribute('data-align');\n this.dom.classList.toggle(\n 'nile-wysiwyg__figure--empty-caption',\n node.content.size === 0\n );\n }\n\n update(node: PMNode): boolean {\n if (node.type !== this.node.type) return false;\n this.node = node;\n this.applyAttrs(node);\n return true;\n }\n\n selectNode(): void {\n this.dom.classList.add('nile-wysiwyg__figure--selected');\n this.wrapper.classList.add('nile-wysiwyg__image-resizer--selected');\n }\n\n deselectNode(): void {\n this.dom.classList.remove('nile-wysiwyg__figure--selected');\n this.wrapper.classList.remove('nile-wysiwyg__image-resizer--selected');\n }\n\n stopEvent(event: Event): boolean {\n return isResizeEvent(event);\n }\n\n ignoreMutation(mutation: MutationRecord): boolean {\n // Caption edits must flow through; image/handle mutations must not.\n return !this.contentDOM.contains(mutation.target);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"image-view.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/image-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { Node as PMNode } from 'prosemirror-model';\nimport { EditorView, NodeView } from 'prosemirror-view';\nimport { NodeSelection } from 'prosemirror-state';\nimport { imageWidthCss } from '../schema';\n\nconst MIN_WIDTH = 40;\n\n/**\n * Attaches four corner drag-handles to a wrapper and returns a cleanup\n * function. Dragging previews by mutating the target's style; on release the\n * final width is committed through onCommit (one transaction).\n */\nexport function attachResizeHandles(\n wrapper: HTMLElement,\n img: HTMLElement,\n onCommit: (width: number) => void,\n minWidth: number = MIN_WIDTH\n): void {\n for (const corner of ['nw', 'ne', 'sw', 'se']) {\n const handle = document.createElement('span');\n handle.className = `nile-wysiwyg__resize-handle nile-wysiwyg__resize-handle--${corner}`;\n handle.dataset.resizeHandle = corner;\n handle.contentEditable = 'false';\n handle.addEventListener('mousedown', event => {\n event.preventDefault();\n event.stopPropagation();\n const startX = event.clientX;\n const startWidth = img.getBoundingClientRect().width;\n const sign = corner.includes('w') ? -1 : 1;\n const maxWidth =\n wrapper.closest('.ProseMirror')?.getBoundingClientRect().width ?? 2000;\n let width = startWidth;\n const onMove = (move: MouseEvent): void => {\n width = Math.max(\n minWidth,\n Math.min(maxWidth, startWidth + sign * (move.clientX - startX))\n );\n img.style.width = `${Math.round(width)}px`;\n };\n const onUp = (): void => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n wrapper.classList.remove('nile-wysiwyg__resizing');\n onCommit(Math.round(width));\n };\n // While dragging, iframes inside the wrapper must not swallow mouse\n // events (they are separate documents); CSS keys off this class.\n wrapper.classList.add('nile-wysiwyg__resizing');\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n });\n wrapper.appendChild(handle);\n }\n}\n\nexport function isResizeEvent(event: Event): boolean {\n return (\n event.target instanceof HTMLElement && !!event.target.dataset.resizeHandle\n );\n}\n\n/** Inline image with drag-resize handles shown while selected. */\nexport class ImageView implements NodeView {\n dom: HTMLSpanElement;\n\n private img: HTMLImageElement;\n\n constructor(\n private node: PMNode,\n view: EditorView,\n getPos: () => number | undefined\n ) {\n this.dom = document.createElement('span');\n this.dom.className = 'nile-wysiwyg__image-resizer';\n this.img = document.createElement('img');\n this.applyAttrs(node);\n this.dom.appendChild(this.img);\n attachResizeHandles(this.dom, this.img, width => {\n const pos = getPos();\n if (pos === undefined || !view.editable) return;\n const current = view.state.doc.nodeAt(pos);\n if (!current) return;\n view.dispatch(\n view.state.tr.setNodeMarkup(pos, undefined, { ...current.attrs, width })\n );\n });\n }\n\n private applyAttrs(node: PMNode): void {\n const { src, alt, title, width } = node.attrs;\n this.img.src = src;\n if (alt) this.img.alt = alt;\n else this.img.removeAttribute('alt');\n if (title) this.img.title = title;\n else this.img.removeAttribute('title');\n this.img.style.width = imageWidthCss(width) ?? '';\n }\n\n update(node: PMNode): boolean {\n if (node.type !== this.node.type) return false;\n this.node = node;\n this.applyAttrs(node);\n return true;\n }\n\n selectNode(): void {\n this.dom.classList.add('nile-wysiwyg__image-resizer--selected');\n }\n\n deselectNode(): void {\n this.dom.classList.remove('nile-wysiwyg__image-resizer--selected');\n }\n\n stopEvent(event: Event): boolean {\n return isResizeEvent(event);\n }\n\n ignoreMutation(): boolean {\n return true;\n }\n}\n\n/**\n * Captioned figure: non-editable image (with resize handles) above an\n * editable figcaption (the node's content). Clicking the image selects the\n * whole figure.\n */\nexport class FigureView implements NodeView {\n dom: HTMLElement;\n\n contentDOM: HTMLElement;\n\n private img: HTMLImageElement;\n\n private wrapper: HTMLSpanElement;\n\n constructor(\n private node: PMNode,\n view: EditorView,\n getPos: () => number | undefined\n ) {\n this.dom = document.createElement('figure');\n this.dom.className = 'nile-wysiwyg__figure';\n\n this.wrapper = document.createElement('span');\n this.wrapper.className = 'nile-wysiwyg__image-resizer';\n this.wrapper.contentEditable = 'false';\n this.img = document.createElement('img');\n this.wrapper.appendChild(this.img);\n\n this.contentDOM = document.createElement('figcaption');\n this.contentDOM.className = 'nile-wysiwyg__figcaption';\n\n this.dom.append(this.wrapper, this.contentDOM);\n this.applyAttrs(node);\n\n // Clicking the image selects the figure node (instead of dropping the\n // cursor into the caption).\n this.img.addEventListener('mousedown', event => {\n event.preventDefault();\n const pos = getPos();\n if (pos === undefined) return;\n view.dispatch(\n view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos))\n );\n view.focus();\n });\n\n attachResizeHandles(this.wrapper, this.img, width => {\n const pos = getPos();\n if (pos === undefined || !view.editable) return;\n const current = view.state.doc.nodeAt(pos);\n if (!current) return;\n view.dispatch(\n view.state.tr.setNodeMarkup(pos, undefined, { ...current.attrs, width })\n );\n });\n }\n\n private applyAttrs(node: PMNode): void {\n const { src, alt, title, width, align } = node.attrs;\n this.img.src = src;\n if (alt) this.img.alt = alt;\n else this.img.removeAttribute('alt');\n if (title) this.img.title = title;\n else this.img.removeAttribute('title');\n this.dom.style.width = imageWidthCss(width) ?? '';\n if (align) this.dom.setAttribute('data-align', align);\n else this.dom.removeAttribute('data-align');\n this.dom.classList.toggle(\n 'nile-wysiwyg__figure--empty-caption',\n node.content.size === 0\n );\n }\n\n update(node: PMNode): boolean {\n if (node.type !== this.node.type) return false;\n this.node = node;\n this.applyAttrs(node);\n return true;\n }\n\n selectNode(): void {\n this.dom.classList.add('nile-wysiwyg__figure--selected');\n this.wrapper.classList.add('nile-wysiwyg__image-resizer--selected');\n }\n\n deselectNode(): void {\n this.dom.classList.remove('nile-wysiwyg__figure--selected');\n this.wrapper.classList.remove('nile-wysiwyg__image-resizer--selected');\n }\n\n stopEvent(event: Event): boolean {\n return isResizeEvent(event);\n }\n\n ignoreMutation(mutation: MutationRecord): boolean {\n // Caption edits must flow through; image/handle mutations must not.\n return !this.contentDOM.contains(mutation.target);\n }\n}\n"]}
|
|
@@ -7,5 +7,9 @@ export interface LinkPluginOptions {
|
|
|
7
7
|
* Link behaviors that belong to the document, not the chrome:
|
|
8
8
|
* - Mod/Ctrl-click opens the link.
|
|
9
9
|
* - Pasting a bare URL over a text selection turns the selection into a link.
|
|
10
|
+
* - Typing over a selection that is entirely one link keeps the link, for the
|
|
11
|
+
* replaced text and for the characters typed straight after it (the link mark
|
|
12
|
+
* is non-inclusive, so without this the new label drops out of the link — an
|
|
13
|
+
* email button renamed by retyping lost its href).
|
|
10
14
|
*/
|
|
11
15
|
export declare function linkPlugin(options?: LinkPluginOptions): Plugin;
|
|
@@ -1,14 +1,69 @@
|
|
|
1
|
-
import { Plugin } from 'prosemirror-state';
|
|
1
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
2
2
|
import { isSafeUrl } from '../sanitize';
|
|
3
3
|
const URL_PATTERN = /^https?:\/\/\S+$/i;
|
|
4
|
+
const retypeKey = new PluginKey('nile-wysiwyg-link-retype');
|
|
5
|
+
/** The link mark covering every text node in [from, to), or null. */
|
|
6
|
+
function linkCovering(state, from, to) {
|
|
7
|
+
const type = state.schema.marks.link;
|
|
8
|
+
let mark = null;
|
|
9
|
+
let covered = true;
|
|
10
|
+
state.doc.nodesBetween(from, to, node => {
|
|
11
|
+
if (!covered || !node.isText)
|
|
12
|
+
return;
|
|
13
|
+
const found = type.isInSet(node.marks);
|
|
14
|
+
if (!found || (mark && !found.eq(mark)))
|
|
15
|
+
covered = false;
|
|
16
|
+
else
|
|
17
|
+
mark = found;
|
|
18
|
+
});
|
|
19
|
+
return covered ? mark : null;
|
|
20
|
+
}
|
|
4
21
|
/**
|
|
5
22
|
* Link behaviors that belong to the document, not the chrome:
|
|
6
23
|
* - Mod/Ctrl-click opens the link.
|
|
7
24
|
* - Pasting a bare URL over a text selection turns the selection into a link.
|
|
25
|
+
* - Typing over a selection that is entirely one link keeps the link, for the
|
|
26
|
+
* replaced text and for the characters typed straight after it (the link mark
|
|
27
|
+
* is non-inclusive, so without this the new label drops out of the link — an
|
|
28
|
+
* email button renamed by retyping lost its href).
|
|
8
29
|
*/
|
|
9
30
|
export function linkPlugin(options = {}) {
|
|
10
31
|
return new Plugin({
|
|
32
|
+
key: retypeKey,
|
|
33
|
+
state: {
|
|
34
|
+
init: () => null,
|
|
35
|
+
apply(tr, prev) {
|
|
36
|
+
const meta = tr.getMeta(retypeKey);
|
|
37
|
+
if (meta !== undefined)
|
|
38
|
+
return meta;
|
|
39
|
+
if (!prev)
|
|
40
|
+
return null;
|
|
41
|
+
// Any caret move, or an edit elsewhere, ends the retype run.
|
|
42
|
+
if (!tr.docChanged)
|
|
43
|
+
return tr.selectionSet ? null : prev;
|
|
44
|
+
const pos = tr.mapping.map(prev.pos);
|
|
45
|
+
return tr.selection.empty && tr.selection.from === pos ? { ...prev, pos } : null;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
11
48
|
props: {
|
|
49
|
+
handleTextInput(view, from, to, text) {
|
|
50
|
+
const { state } = view;
|
|
51
|
+
let mark = null;
|
|
52
|
+
if (from < to)
|
|
53
|
+
mark = linkCovering(state, from, to);
|
|
54
|
+
else {
|
|
55
|
+
const run = retypeKey.getState(state);
|
|
56
|
+
if (run && run.pos === from)
|
|
57
|
+
mark = run.mark;
|
|
58
|
+
}
|
|
59
|
+
if (!mark)
|
|
60
|
+
return false;
|
|
61
|
+
const end = from + text.length;
|
|
62
|
+
const tr = state.tr.insertText(text, from, to).addMark(from, end, mark);
|
|
63
|
+
tr.setMeta(retypeKey, { pos: end, mark });
|
|
64
|
+
view.dispatch(tr);
|
|
65
|
+
return true;
|
|
66
|
+
},
|
|
12
67
|
handleClick(view, _pos, event) {
|
|
13
68
|
if (!(event.metaKey || event.ctrlKey))
|
|
14
69
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/link.ts"],"names":[],"mappings":"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","sourcesContent":["import { Plugin, PluginKey, EditorState } from 'prosemirror-state';\nimport { Mark } from 'prosemirror-model';\nimport { isSafeUrl } from '../sanitize';\n\nconst URL_PATTERN = /^https?:\\/\\/\\S+$/i;\n\nexport interface LinkPluginOptions {\n /** Called with the href when a link is Mod/Ctrl-clicked. */\n onOpenLink?: (href: string) => void;\n}\n\n/** Where retyped link text continues: the caret position and the link it keeps. */\ninterface RetypeState {\n pos: number;\n mark: Mark;\n}\n\nconst retypeKey = new PluginKey<RetypeState | null>('nile-wysiwyg-link-retype');\n\n/** The link mark covering every text node in [from, to), or null. */\nfunction linkCovering(state: EditorState, from: number, to: number): Mark | null {\n const type = state.schema.marks.link;\n let mark: Mark | null = null;\n let covered = true;\n state.doc.nodesBetween(from, to, node => {\n if (!covered || !node.isText) return;\n const found = type.isInSet(node.marks);\n if (!found || (mark && !found.eq(mark))) covered = false;\n else mark = found;\n });\n return covered ? mark : null;\n}\n\n/**\n * Link behaviors that belong to the document, not the chrome:\n * - Mod/Ctrl-click opens the link.\n * - Pasting a bare URL over a text selection turns the selection into a link.\n * - Typing over a selection that is entirely one link keeps the link, for the\n * replaced text and for the characters typed straight after it (the link mark\n * is non-inclusive, so without this the new label drops out of the link — an\n * email button renamed by retyping lost its href).\n */\nexport function linkPlugin(options: LinkPluginOptions = {}): Plugin {\n return new Plugin<RetypeState | null>({\n key: retypeKey,\n state: {\n init: () => null,\n apply(tr, prev) {\n const meta = tr.getMeta(retypeKey) as RetypeState | null | undefined;\n if (meta !== undefined) return meta;\n if (!prev) return null;\n // Any caret move, or an edit elsewhere, ends the retype run.\n if (!tr.docChanged) return tr.selectionSet ? null : prev;\n const pos = tr.mapping.map(prev.pos);\n return tr.selection.empty && tr.selection.from === pos ? { ...prev, pos } : null;\n },\n },\n props: {\n handleTextInput(view, from, to, text) {\n const { state } = view;\n let mark: Mark | null = null;\n if (from < to) mark = linkCovering(state, from, to);\n else {\n const run = retypeKey.getState(state);\n if (run && run.pos === from) mark = run.mark;\n }\n if (!mark) return false;\n const end = from + text.length;\n const tr = state.tr.insertText(text, from, to).addMark(from, end, mark);\n tr.setMeta(retypeKey, { pos: end, mark });\n view.dispatch(tr);\n return true;\n },\n\n handleClick(view, _pos, event) {\n if (!(event.metaKey || event.ctrlKey)) return false;\n const target = (event.target as HTMLElement | null)?.closest?.('a[href]');\n if (!target) return false;\n const href = target.getAttribute('href')!;\n if (!isSafeUrl(href)) return false;\n if (options.onOpenLink) options.onOpenLink(href);\n else window.open(href, '_blank', 'noopener,noreferrer');\n return true;\n },\n\n handlePaste(view, event) {\n const { state } = view;\n const { empty, from, to } = state.selection;\n if (empty) return false;\n const text = event.clipboardData?.getData('text/plain')?.trim();\n if (!text || !URL_PATTERN.test(text) || !isSafeUrl(text)) return false;\n const linkMark = state.schema.marks.link.create({ href: text });\n view.dispatch(state.tr.addMark(from, to, linkMark));\n return true;\n },\n },\n });\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Plugin } from 'prosemirror-state';
|
|
2
2
|
import { Slice, Schema } from 'prosemirror-model';
|
|
3
|
+
import { NormalizedAllowedStyles } from '../email-css';
|
|
3
4
|
/**
|
|
4
5
|
* Builds a slice of plain paragraphs from text, splitting on newlines. Open
|
|
5
6
|
* depth 1 on both ends lets the first/last block merge into the surrounding
|
|
@@ -22,6 +23,10 @@ export interface PasteOptions {
|
|
|
22
23
|
getMarkdownPaste?: () => boolean;
|
|
23
24
|
/** Read live: whether pasted HTML is sanitized. Defaults to on. */
|
|
24
25
|
getSanitize?: () => boolean;
|
|
26
|
+
/** Read live: when true, HTML-looking plain text is parsed as HTML (email fidelity). */
|
|
27
|
+
getEmailFidelity?: () => boolean;
|
|
28
|
+
/** Read live: the validated per-app email-fidelity style allowlist. */
|
|
29
|
+
getAllowedStyles?: () => NormalizedAllowedStyles;
|
|
25
30
|
}
|
|
26
31
|
/**
|
|
27
32
|
* Paste behavior: plain-text pastes that look like Markdown are parsed into
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Plugin } from 'prosemirror-state';
|
|
2
2
|
import { Slice, Fragment } from 'prosemirror-model';
|
|
3
3
|
import { markdownToHtml, looksLikeMarkdown } from '../markdown-parse';
|
|
4
|
-
import {
|
|
4
|
+
import { looksLikeHtml } from '../html-detect';
|
|
5
|
+
import { htmlToDoc, htmlToSlice } from '../serializer';
|
|
5
6
|
/**
|
|
6
7
|
* Builds a slice of plain paragraphs from text, splitting on newlines. Open
|
|
7
8
|
* depth 1 on both ends lets the first/last block merge into the surrounding
|
|
@@ -26,10 +27,6 @@ export function pastePlugin(schema, options = {}) {
|
|
|
26
27
|
return new Plugin({
|
|
27
28
|
props: {
|
|
28
29
|
handlePaste(view, event) {
|
|
29
|
-
if (options.getForcePlainText?.())
|
|
30
|
-
return false;
|
|
31
|
-
if (options.getMarkdownPaste && !options.getMarkdownPaste())
|
|
32
|
-
return false;
|
|
33
30
|
// Only plain-text pastes qualify: an HTML flavor means the source
|
|
34
31
|
// was already rich, and code blocks take text verbatim.
|
|
35
32
|
const html = event.clipboardData?.getData('text/html') ?? '';
|
|
@@ -38,9 +35,33 @@ export function pastePlugin(schema, options = {}) {
|
|
|
38
35
|
return false;
|
|
39
36
|
if (view.state.selection.$from.parent.type.spec.code)
|
|
40
37
|
return false;
|
|
38
|
+
const forcePlain = options.getForcePlainText?.() ?? false;
|
|
39
|
+
const sanitize = options.getSanitize?.() ?? true;
|
|
40
|
+
// Precedence: paste-as-plain-text → HTML detection (fidelity) → Markdown.
|
|
41
|
+
if (looksLikeHtml(text)) {
|
|
42
|
+
if (options.getEmailFidelity?.() && !forcePlain) {
|
|
43
|
+
// Closed slice so the whole document (tables, blocks) lands intact
|
|
44
|
+
// rather than being opened and merged into the target paragraph.
|
|
45
|
+
const doc = htmlToDoc(schema, text, sanitize, {
|
|
46
|
+
emailFidelity: true,
|
|
47
|
+
allowedStyles: options.getAllowedStyles?.(),
|
|
48
|
+
});
|
|
49
|
+
const slice = new Slice(doc.content, 0, 0);
|
|
50
|
+
view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const slice = plainTextSlice(schema, text);
|
|
54
|
+
view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (forcePlain)
|
|
59
|
+
return false;
|
|
60
|
+
if (options.getMarkdownPaste && !options.getMarkdownPaste())
|
|
61
|
+
return false;
|
|
41
62
|
if (!looksLikeMarkdown(text))
|
|
42
63
|
return false;
|
|
43
|
-
const slice = htmlToSlice(schema, markdownToHtml(text),
|
|
64
|
+
const slice = htmlToSlice(schema, markdownToHtml(text), sanitize);
|
|
44
65
|
view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
|
|
45
66
|
return true;
|
|
46
67
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paste.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/paste.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAA0B,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"paste.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/paste.ts"],"names":[],"mappings":"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","sourcesContent":["import { Plugin } from 'prosemirror-state';\nimport { Slice, Fragment, Node as PMNode, Schema } from 'prosemirror-model';\nimport { markdownToHtml, looksLikeMarkdown } from '../markdown-parse';\nimport { looksLikeHtml } from '../html-detect';\nimport { htmlToDoc, htmlToSlice } from '../serializer';\nimport { NormalizedAllowedStyles } from '../email-css';\n\n/**\n * Builds a slice of plain paragraphs from text, splitting on newlines. Open\n * depth 1 on both ends lets the first/last block merge into the surrounding\n * paragraph, matching how a normal plain-text paste behaves.\n */\nexport function plainTextSlice(schema: Schema, text: string): Slice {\n const blocks = text.split(/\\r\\n?|\\n/);\n const nodes: PMNode[] = blocks.map(line =>\n schema.nodes.paragraph.create(null, line ? schema.text(line) : null)\n );\n return new Slice(Fragment.from(nodes), 1, 1);\n}\n\n/** Reduces a pasted slice to unstyled text, preserving block breaks. */\nexport function stripSliceFormatting(schema: Schema, slice: Slice): Slice {\n const text = slice.content.textBetween(0, slice.content.size, '\\n', '\\n');\n return plainTextSlice(schema, text);\n}\n\nexport interface PasteOptions {\n /**\n * Read live: when it returns true, every paste drops formatting (the\n * persistent \"paste as plain text\" toggle). The Ctrl+Shift+V shortcut is a\n * separate one-shot handled in the keymap.\n */\n getForcePlainText?: () => boolean;\n /**\n * Read live: when false, plain-text pastes are never parsed as Markdown.\n * Defaults to on.\n */\n getMarkdownPaste?: () => boolean;\n /** Read live: whether pasted HTML is sanitized. Defaults to on. */\n getSanitize?: () => boolean;\n /** Read live: when true, HTML-looking plain text is parsed as HTML (email fidelity). */\n getEmailFidelity?: () => boolean;\n /** Read live: the validated per-app email-fidelity style allowlist. */\n getAllowedStyles?: () => NormalizedAllowedStyles;\n}\n\n/**\n * Paste behavior: plain-text pastes that look like Markdown are parsed into\n * rich content (headings, lists, code fences, tables, inline marks), and all\n * pastes drop formatting while the host's plain-text toggle is on.\n */\nexport function pastePlugin(schema: Schema, options: PasteOptions = {}): Plugin {\n return new Plugin({\n props: {\n handlePaste(view, event) {\n // Only plain-text pastes qualify: an HTML flavor means the source\n // was already rich, and code blocks take text verbatim.\n const html = event.clipboardData?.getData('text/html') ?? '';\n const text = event.clipboardData?.getData('text/plain') ?? '';\n if (html.trim() || !text.trim()) return false;\n if (view.state.selection.$from.parent.type.spec.code) return false;\n const forcePlain = options.getForcePlainText?.() ?? false;\n const sanitize = options.getSanitize?.() ?? true;\n\n // Precedence: paste-as-plain-text → HTML detection (fidelity) → Markdown.\n if (looksLikeHtml(text)) {\n if (options.getEmailFidelity?.() && !forcePlain) {\n // Closed slice so the whole document (tables, blocks) lands intact\n // rather than being opened and merged into the target paragraph.\n const doc = htmlToDoc(schema, text, sanitize, {\n emailFidelity: true,\n allowedStyles: options.getAllowedStyles?.(),\n });\n const slice = new Slice(doc.content, 0, 0);\n view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());\n } else {\n const slice = plainTextSlice(schema, text);\n view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());\n }\n return true;\n }\n\n if (forcePlain) return false;\n if (options.getMarkdownPaste && !options.getMarkdownPaste()) return false;\n if (!looksLikeMarkdown(text)) return false;\n const slice = htmlToSlice(schema, markdownToHtml(text), sanitize);\n view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());\n return true;\n },\n transformPasted(slice) {\n return options.getForcePlainText?.()\n ? stripSliceFormatting(schema, slice)\n : slice;\n },\n },\n });\n}\n"]}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { tableEditing, columnResizing, TableView } from 'prosemirror-tables';
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
*/
|
|
2
|
+
import { tableStyles } from '../schema';
|
|
3
|
+
/** TableView that also puts the author's class/id and fidelity table styles on the inner `<table>`. */
|
|
9
4
|
class HtmlAttrTableView extends TableView {
|
|
10
5
|
constructor(node, defaultCellMinWidth) {
|
|
11
6
|
super(node, defaultCellMinWidth);
|
|
@@ -19,6 +14,34 @@ class HtmlAttrTableView extends TableView {
|
|
|
19
14
|
this.table.id = htmlId;
|
|
20
15
|
else
|
|
21
16
|
this.table.removeAttribute('id');
|
|
17
|
+
// Email-fidelity attrs (width, max-width, background, border, centring).
|
|
18
|
+
// Width is only overridden when set, so column-resize sizing still applies.
|
|
19
|
+
const style = this.table.style;
|
|
20
|
+
// tableStyles() entries can hold several declarations ('color: x; font-family: y'
|
|
21
|
+
// for the table text style or an allowedStyles extension), so flatten them first.
|
|
22
|
+
const decls = tableStyles(node.attrs)
|
|
23
|
+
.flatMap(entry => entry.split(';'))
|
|
24
|
+
.map(decl => decl.trim())
|
|
25
|
+
.filter(decl => decl.includes(':'));
|
|
26
|
+
for (const prop of [
|
|
27
|
+
'max-width', 'background-color', 'border', 'margin-left', 'margin-right',
|
|
28
|
+
'color', 'font-family', 'font-size', 'font-weight', 'line-height',
|
|
29
|
+
]) {
|
|
30
|
+
style.removeProperty(prop);
|
|
31
|
+
}
|
|
32
|
+
// Clear any per-app extension properties first so a value that changed (or an
|
|
33
|
+
// entry that was removed) doesn't linger from the previous application.
|
|
34
|
+
for (const decl of decls)
|
|
35
|
+
style.removeProperty(decl.slice(0, decl.indexOf(':')).trim());
|
|
36
|
+
for (const decl of decls) {
|
|
37
|
+
const idx = decl.indexOf(':');
|
|
38
|
+
style.setProperty(decl.slice(0, idx).trim(), decl.slice(idx + 1).trim());
|
|
39
|
+
}
|
|
40
|
+
// A layout table with no width of its own (an email button) shrinks to fit
|
|
41
|
+
// under email-fidelity; the host CSS keys off this hook.
|
|
42
|
+
this.table.toggleAttribute('data-autowidth', Boolean(node.attrs.layout && !node.attrs.width));
|
|
43
|
+
// Lets the host CSS drop column resizing's min-width on layout tables.
|
|
44
|
+
this.table.toggleAttribute('data-layout-table', Boolean(node.attrs.layout));
|
|
22
45
|
}
|
|
23
46
|
update(node) {
|
|
24
47
|
const updated = super.update(node);
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../../src/nile-wysiwyg-editor/engine/plugins/tables.ts"],"names":[],"mappings":"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","sourcesContent":["import { Plugin } from 'prosemirror-state';\nimport { Node as PMNode } from 'prosemirror-model';\nimport { tableEditing, columnResizing, TableView } from 'prosemirror-tables';\nimport { tableStyles } from '../schema';\n\n/** TableView that also puts the author's class/id and fidelity table styles on the inner `<table>`. */\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 // Email-fidelity attrs (width, max-width, background, border, centring).\n // Width is only overridden when set, so column-resize sizing still applies.\n const style = this.table.style;\n // tableStyles() entries can hold several declarations ('color: x; font-family: y'\n // for the table text style or an allowedStyles extension), so flatten them first.\n const decls = tableStyles(node.attrs)\n .flatMap(entry => entry.split(';'))\n .map(decl => decl.trim())\n .filter(decl => decl.includes(':'));\n for (const prop of [\n 'max-width', 'background-color', 'border', 'margin-left', 'margin-right',\n 'color', 'font-family', 'font-size', 'font-weight', 'line-height',\n ]) {\n style.removeProperty(prop);\n }\n // Clear any per-app extension properties first so a value that changed (or an\n // entry that was removed) doesn't linger from the previous application.\n for (const decl of decls) style.removeProperty(decl.slice(0, decl.indexOf(':')).trim());\n for (const decl of decls) {\n const idx = decl.indexOf(':');\n style.setProperty(decl.slice(0, idx).trim(), decl.slice(idx + 1).trim());\n }\n // A layout table with no width of its own (an email button) shrinks to fit\n // under email-fidelity; the host CSS keys off this hook.\n this.table.toggleAttribute('data-autowidth', Boolean(node.attrs.layout && !node.attrs.width));\n // Lets the host CSS drop column resizing's min-width on layout tables.\n this.table.toggleAttribute('data-layout-table', Boolean(node.attrs.layout));\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"]}
|
|
@@ -763,6 +763,52 @@ describe('figure & image commands', () => {
|
|
|
763
763
|
expect(docToHtml(state.doc)).to.not.include('<img');
|
|
764
764
|
});
|
|
765
765
|
});
|
|
766
|
+
describe('image percentage widths (fix 1, global)', () => {
|
|
767
|
+
const ON = { emailFidelity: true };
|
|
768
|
+
/** First <img> style.width after a full htmlToDoc→docToHtml round-trip. */
|
|
769
|
+
function imgWidth(html, on = false) {
|
|
770
|
+
const doc = on
|
|
771
|
+
? htmlToDoc(defaultSchema, html, true, ON)
|
|
772
|
+
: htmlToDoc(defaultSchema, html);
|
|
773
|
+
const out = docToHtml(doc);
|
|
774
|
+
const m = new DOMParser().parseFromString(out, 'text/html');
|
|
775
|
+
return m.querySelector('img')?.style.width ?? '';
|
|
776
|
+
}
|
|
777
|
+
it('round-trips width:100% as a percentage with the flag off', () => {
|
|
778
|
+
expect(imgWidth('<p><img src="https://x.co/i.png" style="width:100%"></p>')).to.equal('100%');
|
|
779
|
+
});
|
|
780
|
+
it('round-trips width:100% as a percentage with the flag on', () => {
|
|
781
|
+
expect(imgWidth('<p><img src="https://x.co/i.png" style="width:100%"></p>', true)).to.equal('100%');
|
|
782
|
+
});
|
|
783
|
+
it('keeps a fractional percentage (50.5%)', () => {
|
|
784
|
+
expect(imgWidth('<p><img src="https://x.co/i.png" style="width:50.5%"></p>')).to.equal('50.5%');
|
|
785
|
+
});
|
|
786
|
+
it('still emits a pixel width for width:320px', () => {
|
|
787
|
+
expect(imgWidth('<p><img src="https://x.co/i.png" style="width:320px"></p>')).to.equal('320px');
|
|
788
|
+
});
|
|
789
|
+
it('falls back to the width attribute (px) when there is no style width', () => {
|
|
790
|
+
expect(imgWidth('<p><img src="https://x.co/i.png" width="1232"></p>')).to.equal('1232px');
|
|
791
|
+
});
|
|
792
|
+
it('drops an out-of-range percentage (150%)', () => {
|
|
793
|
+
const out = docToHtml(htmlToDoc(defaultSchema, '<p><img src="https://x.co/i.png" style="width:150%"></p>'));
|
|
794
|
+
expect(out).to.not.include('150%');
|
|
795
|
+
expect(out).to.not.include('width: 150');
|
|
796
|
+
});
|
|
797
|
+
it('drops a calc() width', () => {
|
|
798
|
+
const out = docToHtml(htmlToDoc(defaultSchema, '<p><img src="https://x.co/i.png" style="width:calc(100% - 2px)"></p>', true, ON));
|
|
799
|
+
expect(out).to.not.include('calc(');
|
|
800
|
+
});
|
|
801
|
+
it('round-trips a percentage width on a figure', () => {
|
|
802
|
+
const out = docToHtml(htmlToDoc(defaultSchema, '<figure><img src="https://x.co/i.png" style="width:50%"><figcaption>c</figcaption></figure>'));
|
|
803
|
+
expect(out).to.include('width: 50%');
|
|
804
|
+
});
|
|
805
|
+
it('serialize → parse → serialize is a fixpoint for a percentage width', () => {
|
|
806
|
+
const src = '<p><img src="https://x.co/i.png" style="width:100%"></p>';
|
|
807
|
+
const once = docToHtml(htmlToDoc(defaultSchema, src, true, ON));
|
|
808
|
+
const twice = docToHtml(htmlToDoc(defaultSchema, once, true, ON));
|
|
809
|
+
expect(twice).to.equal(once);
|
|
810
|
+
});
|
|
811
|
+
});
|
|
766
812
|
describe('paste from Office', () => {
|
|
767
813
|
it('detects Word and Google Docs clipboard HTML', () => {
|
|
768
814
|
expect(isOfficeHtml('<p class="MsoNormal">x</p>')).to.equal(true);
|