Skip to content

Comments

Widget richtext#7162

Open
demshy wants to merge 54 commits intodecaporg:mainfrom
poslovnimediji:widget-richtext
Open

Widget richtext#7162
demshy wants to merge 54 commits intodecaporg:mainfrom
poslovnimediji:widget-richtext

Conversation

@demshy
Copy link
Member

@demshy demshy commented Mar 27, 2024

Summary
This is a work-in-progress PR that adds richtext-widget as a potential replacement for the markdown in one of the future releases. Discussion where I put some of my thoughts about this here: #6905
Digging deeper, there might be another caveat that we haven't considered before - nesting block types (inside lists for example) might make the implementation much more difficult so I did not go down that road yet.

A very rough checklist:

  • create new widget and install Plate
  • inline marks (bold, italics, and code)
  • headings
  • number and bullet lists
  • quote block
  • links
  • editor components / shortcodes
  • toggle markdown view
  • images
  • (new/bonus) tables
  • (new/bonus) drag&drop blocks

I have copied serializers (and their tests) from the existing markdown widget and am updating them as I go. I copy the renderers one by one as I get to the plugin in question.
Once the basic implementation is done, I plan on going through the e2e tests and update what is needed on the code or tests side, depends on the specific situation.

Note that this is very much in progress but I'm happy of any feedback, especially from someone who dealt with Slate/Plate before.

Test plan

Checklist

Please add a x inside each checkbox:

A picture of a cute animal (not mandatory but encouraged)

@demshy demshy force-pushed the widget-richtext branch from bcd8f04 to 181d644 Compare April 4, 2024 13:28
RaphaelBossek added a commit to RaphaelBossek/decap-cms that referenced this pull request Dec 1, 2024
@demshy demshy mentioned this pull request Oct 1, 2025
1 task
@martinjagodic
Copy link
Member

Tables are not rendered in rich text mode as they are in the markdown widget.

Screen.Recording.2025-12-10.at.15.17.32.mov

@martinjagodic martinjagodic marked this pull request as ready for review February 23, 2026 12:55
@martinjagodic martinjagodic requested a review from a team as a code owner February 23, 2026 12:55
@yanthomasdev yanthomasdev requested a review from Copilot February 24, 2026 16:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new richtext widget package (based on Plate) and wires it into the app/preview pipeline as an experimental alternative to the existing markdown widget.

Changes:

  • Added decap-cms-widget-richtext package: control/editor UI, serializers (Markdown/HTML/Slate), and unit tests.
  • Integrated richtext widget into the app registry and preview context (passes getEditorComponents through preview).
  • Added/updated dev-test and Cypress e2e coverage to exercise richtext behavior.

Reviewed changes

Copilot reviewed 89 out of 91 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tsconfig.json Switch TS module settings to NodeNext and add a path alias for decap-cms-ui-default.
packages/decap-cms-widget-richtext/webpack.config.js Adds webpack config for the new widget package.
packages/decap-cms-widget-richtext/test-helpers/h.js Slate hyperscript helper for serializer tests.
packages/decap-cms-widget-richtext/src/styles.js Shared richtext editor styling primitives.
packages/decap-cms-widget-richtext/src/serializers/slateRemark.js Slate→MDAST serializer port/adaptation.
packages/decap-cms-widget-richtext/src/serializers/remarkWrapHtml.js Remark plugin to wrap top-level html nodes.
packages/decap-cms-widget-richtext/src/serializers/remarkStripTrailingBreaks.js Remark plugin to remove trailing breaks.
packages/decap-cms-widget-richtext/src/serializers/remarkSquashReferences.js Squashes link/image references to inline forms.
packages/decap-cms-widget-richtext/src/serializers/remarkSlate.js MDAST→Slate serializer with mark/text normalization.
packages/decap-cms-widget-richtext/src/serializers/remarkShortcodes.js Parses and stringifies editor-component shortcodes.
packages/decap-cms-widget-richtext/src/serializers/remarkRehypeShortcodes.js Prepares shortcode previews for remark→rehype conversion.
packages/decap-cms-widget-richtext/src/serializers/remarkPaddedLinks.js Fixes padded link text edge cases.
packages/decap-cms-widget-richtext/src/serializers/remarkImagesToText.js Converts certain image nodes to text for shortcode matching.
packages/decap-cms-widget-richtext/src/serializers/remarkEscapeMarkdownEntities.js Escapes markdown entities in non-markdown-aware text.
packages/decap-cms-widget-richtext/src/serializers/remarkAssertParents.js Unwraps invalid MDAST nesting from pasted HTML.
packages/decap-cms-widget-richtext/src/serializers/remarkAllowHtmlEntities.js Prevents HTML entity decoding during remark parsing.
packages/decap-cms-widget-richtext/src/serializers/rehypePaperEmoji.js Replaces Paper emoji images with actual emoji chars.
packages/decap-cms-widget-richtext/src/serializers/regexHelper.js Shared regex utilities for serializer plugins.
packages/decap-cms-widget-richtext/src/serializers/index.js Serializer orchestration for markdown↔slate↔html.
packages/decap-cms-widget-richtext/src/serializers/tests/slate.spec.js Slate serializer test suite.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkStripTrailingBreaks.spec.js Tests for stripping trailing breaks.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkSlate.spec.js Tests for mergeAdjacentTexts.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkShortcodes.spec.js Tests for shortcode parsing/tokenization helpers.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkPlugins.spec.js Verifies remark plugins are applied in pipelines.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkPaddedLinks.spec.js Tests padded-link normalization.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkEscapeMarkdownEntities.spec.js Tests markdown entity escaping.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkAssertParents.spec.js Tests invalid-nesting unwrapping.
packages/decap-cms-widget-richtext/src/serializers/tests/remarkAllowHtmlEntities.spec.js Tests entity decoding behavior.
packages/decap-cms-widget-richtext/src/serializers/tests/index.spec.js Serializer integration tests with fixtures.
packages/decap-cms-widget-richtext/src/serializers/tests/commonmark.spec.js CommonMark compliance suite (skipped).
packages/decap-cms-widget-richtext/src/serializers/tests/snapshots/remarkShortcodes.spec.js.snap Jest snapshots for shortcode parsing tests.
packages/decap-cms-widget-richtext/src/serializers/tests/fixtures/duplicate_marks_github_issue_3280.md Fixture for mark dedup regression.
packages/decap-cms-widget-richtext/src/schema.js Widget config schema (buttons, modes, editor components).
packages/decap-cms-widget-richtext/src/index.js Widget export/registration entrypoint.
packages/decap-cms-widget-richtext/src/tests/renderer.spec.js Preview rendering tests for richtext widget output.
packages/decap-cms-widget-richtext/src/RichtextPreview.js Preview component (markdown→html + optional sanitization).
packages/decap-cms-widget-richtext/src/RichtextControl/withProps.js Helper to extend components with default props/ref forwarding.
packages/decap-cms-widget-richtext/src/RichtextControl/plugins/TablePlugin.js Plate table element plugins.
packages/decap-cms-widget-richtext/src/RichtextControl/plugins/ShortcodePlugin.js Plate shortcode (void element) plugin.
packages/decap-cms-widget-richtext/src/RichtextControl/plugins/ExtendedBlockquotePlugin.js Custom blockquote behavior for Enter/Backspace.
packages/decap-cms-widget-richtext/src/RichtextControl/mergeMediaConfig.js Merges media config into image editor components.
packages/decap-cms-widget-richtext/src/RichtextControl/linkHandler.js Handles link insertion/removal via prompt + Plate APIs.
packages/decap-cms-widget-richtext/src/RichtextControl/editorContext.js Context provider for editor control + editor components.
packages/decap-cms-widget-richtext/src/RichtextControl/defaultEmptyBlock.js Creates default empty paragraph block.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/index.js Toolbar barrel export.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/ToolbarButton.js Toolbar button UI component.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/Toolbar.js Main toolbar with marks/blocks/lists/components + mode toggle.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/MarkToolbarButton.js Mark button glue for Plate toolbar hooks.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/ListToolbarButton.js List button glue for Plate list hooks.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/LinkToolbarButton.js Link button glue + prompt handler.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/HeadingToolbarButton.js Heading dropdown selector + block toggling.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/EditorComponentsToolbarButton.js Dropdown to insert editor-component shortcodes.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Toolbar/BlockquoteToolbarButton.js Blockquote toggle button behavior.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Leaf/CodeLeaf.js Code mark rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/TableRowElement.js Table row rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/TableElement.js Table rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/TableCellElement.js Table cell rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/ShortcodeElement.js Renders embedded editor components as void blocks with nested widget UI.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/ParagraphElement.js Paragraph rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/ListElement.js List/list-item rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/LinkElement.js Link element rendering for Plate.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/HeadingElement.js Heading rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Element/BlockquoteElement.js Blockquote rendering.
packages/decap-cms-widget-richtext/src/RichtextControl/components/Editor.js PlateContent wrapper/editor surface.
packages/decap-cms-widget-richtext/src/RichtextControl/tests/parser.spec.js Markdown→Slate parser snapshot tests.
packages/decap-cms-widget-richtext/src/RichtextControl/tests/snapshots/parser.spec.js.snap Snapshot output for parser tests.
packages/decap-cms-widget-richtext/src/RichtextControl/tests/VisualEditor.spec.js Tests media config merging.
packages/decap-cms-widget-richtext/src/RichtextControl/VisualEditor.js Plate-based visual editor implementation.
packages/decap-cms-widget-richtext/src/RichtextControl/RawEditor.js “Raw markdown” mode editor implementation.
packages/decap-cms-widget-richtext/src/RichtextControl.js Richtext widget control (mode switching, focus handling).
packages/decap-cms-widget-richtext/package.json New package manifest for richtext widget.
packages/decap-cms-widget-richtext/README.md Placeholder README.
packages/decap-cms-widget-object/src/ObjectPreview.js Normalizes non-Immutable field prop to Immutable.
packages/decap-cms-widget-markdown/src/serializers/index.js Adds debug logging to markdown widget serialization.
packages/decap-cms-widget-markdown/src/MarkdownControl/renderers.js Adjusts table cell border styling.
packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js Passes getEditorComponents into preview props.
packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewContent.js Adds propTypes entry for getEditorComponents.
packages/decap-cms-app/src/extensions.js Registers the new richtext widget in the app.
package.json Adds eslint-import-resolver-exports dev dependency.
dev-test/index.html Adds dev-test editor components and renders both richtext + markdown fields.
dev-test/config.yml Switches dev-test body field to richtext and adds markdown comparison fields.
cypress/plugins/index.js Adds a task to rewrite config to use richtext widget.
cypress/e2e/richtext_widget_marks_spec.js E2E test for code mark + nested marks in richtext.
cypress/e2e/richtext_widget_link_spec.js E2E tests for link creation + raw-mode output.
cypress/e2e/richtext_widget_hotkeys_spec.js E2E tests for hotkeys in richtext.
cypress/e2e/richtext_widget_enter_spec.js E2E tests for Enter behavior in richtext.
cypress/e2e/richtext_widget_code_block_spec.js E2E test for code block insertion + raw output.
cypress/e2e/richtext_widget_backspace_spec.js E2E tests for Backspace behavior in richtext.
.eslintrc.js Adds exports resolver config for eslint-import-resolver-exports.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@yanthomasdev yanthomasdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a really big PR, I've found a few things I am not sure about and I think there are a few things still TODO here. I left a few comments and suggestions based on what I found.

There's also conflicts with the branch I can't fix since I have no permission for some reason.


const visualEditor = (
<EditorProvider editorControl={editorControl} editorComponents={getEditorComponents()}>
<div className="cms-editor-visual" ref={this.processRef}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.processRef is not set so this will be undefined

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I removed it.


![](https://pbs.twimg.com/profile_images/678903331176214528/TQTdqGwD.jpg)
`;
const html = await markdownToHtml(value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is meant to test Markdown rendering, why is it being converted to HTML?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test are (almost) the same as on markdown widget to make sure it's backward-compatible. The preview component actially renders HTML instead of markdown, so a conversion must happen beforehand.

Comment on lines 73 to 75
function handleBlockClick() {
console.log('handleBlockClick');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is still a TODO?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a function in the markdown widget, but it's not needed here, so I removed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants