From 3a0a701a9b709cbf0ab54fd60de31492fe06dfe4 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Thu, 27 Jun 2024 11:49:02 +0200 Subject: [PATCH 1/4] fix: enforce empty paragraph when converting from markdown to slate --- .../src/serializers/remarkSlate.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/decap-cms-widget-markdown/src/serializers/remarkSlate.js b/packages/decap-cms-widget-markdown/src/serializers/remarkSlate.js index c4a44c8e93cb..cd631a440eb2 100644 --- a/packages/decap-cms-widget-markdown/src/serializers/remarkSlate.js +++ b/packages/decap-cms-widget-markdown/src/serializers/remarkSlate.js @@ -234,7 +234,6 @@ export default function remarkToSlate({ voidCodeBlock } = {}) { * Convert simple cases that only require a type and children, with no * additional properties. */ - case 'root': case 'paragraph': case 'blockquote': case 'tableRow': @@ -242,6 +241,15 @@ export default function remarkToSlate({ voidCodeBlock } = {}) { return createBlock(typeMap[node.type], nodes); } + /** + * Root element + * If the root node is empty, we need to add a paragraph node to it. + */ + case 'root': { + const children = isEmpty(nodes) ? [createBlock('paragraph')] : nodes; + return createBlock(typeMap[node.type], children); + } + /** * List Items * From 739f4ee1cab888adb8b09d2cbc2313f419d37485 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Fri, 28 Jun 2024 14:17:51 +0200 Subject: [PATCH 2/4] fix: handle unwrapping inline nodes in lists --- .../blocks/transforms/unwrapIfCursorAtStart.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js index 491b50f906f5..503293f2921d 100644 --- a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js +++ b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js @@ -5,18 +5,28 @@ import lowestMatchedAncestor from '../../matchers/lowestMatchedAncestor'; function unwrapIfCursorAtStart(editor, mergeWithPrevious = false) { if (editor.selection.anchor.offset !== 0) return false; - const node = Editor.above(editor, lowestMatchedAncestor(editor, 'non-default')); + let [node, path] = Editor.above(editor, lowestMatchedAncestor(editor, 'non-default')); - if (node[1].length == 0) return false; + if (path.length == 0) return false; - const isHeading = `${node[0].type}`.startsWith('heading-'); + const isHeading = `${node.type}`.startsWith('heading-'); if (isHeading) { Transforms.setNodes(editor, { type: 'paragraph' }); return false; } + const isBlock = Editor.isBlock(editor, node); + const [parentBlock, parentBlockPath] = Editor.above(editor, lowestMatchedAncestor(editor, 'block')); + if (!isBlock) { + if (!Editor.isStart(editor, path, parentBlockPath)) { + return false; + } + + [node, path] = [parentBlock, parentBlockPath]; + } + Editor.withoutNormalizing(editor, () => { - Transforms.unwrapNodes(editor, { match: n => n.type === node[0].type, split: true }); + Transforms.unwrapNodes(editor, { match: n => n.type === node.type, split: true }); if (mergeWithPrevious) { Transforms.mergeNodes(editor); From ebe53e7c1614ea61093d7f7c517a192754e6c672 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Fri, 28 Jun 2024 14:23:36 +0200 Subject: [PATCH 3/4] style: lint code --- .../plugins/blocks/transforms/unwrapIfCursorAtStart.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js index 503293f2921d..7e728a1a5d10 100644 --- a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js +++ b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/transforms/unwrapIfCursorAtStart.js @@ -16,7 +16,10 @@ function unwrapIfCursorAtStart(editor, mergeWithPrevious = false) { } const isBlock = Editor.isBlock(editor, node); - const [parentBlock, parentBlockPath] = Editor.above(editor, lowestMatchedAncestor(editor, 'block')); + const [parentBlock, parentBlockPath] = Editor.above( + editor, + lowestMatchedAncestor(editor, 'block'), + ); if (!isBlock) { if (!Editor.isStart(editor, path, parentBlockPath)) { return false; From f58986c172858cf448318a21cc36473379086ad0 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Wed, 7 Aug 2024 12:35:08 +0200 Subject: [PATCH 4/4] fix: lost focus after backspace after break --- .../plugins/blocks/events/keyDown.js | 9 +++++++++ .../locations/isCursorCollapsedAfterSoftBreak.js | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/locations/isCursorCollapsedAfterSoftBreak.js diff --git a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/events/keyDown.js b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/events/keyDown.js index 7d75353a7105..0ce618dd1403 100644 --- a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/events/keyDown.js +++ b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/events/keyDown.js @@ -1,9 +1,11 @@ import isHotkey from 'is-hotkey'; +import { Editor, Transforms } from 'slate'; import keyDownEnter from './keyDownEnter'; import keyDownBackspace from './keyDownBackspace'; import isCursorInNonDefaultBlock from '../locations/isCursorInNonDefaultBlock'; import toggleBlock from './toggleBlock'; +import isCursorCollapsedAfterSoftBreak from '../locations/isCursorCollapsedAfterSoftBreak'; const HEADING_HOTKEYS = { 'mod+1': 'heading-one', @@ -25,6 +27,13 @@ function keyDown(event, editor) { } } + if (isHotkey('backspace', event) && isCursorCollapsedAfterSoftBreak(editor)) { + const [, path] = Editor.previous(editor); + Transforms.removeNodes(editor, { at: path }); + event.preventDefault(); + return false; + } + if (!isCursorInNonDefaultBlock(editor)) return; if (isHotkey('enter', event)) { diff --git a/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/locations/isCursorCollapsedAfterSoftBreak.js b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/locations/isCursorCollapsedAfterSoftBreak.js new file mode 100644 index 000000000000..7355b0061c90 --- /dev/null +++ b/packages/decap-cms-widget-markdown/src/MarkdownControl/plugins/blocks/locations/isCursorCollapsedAfterSoftBreak.js @@ -0,0 +1,13 @@ +import { Editor, Range } from 'slate'; + +function isCursorCollapsedAfterSoftBreak(editor) { + const { selection } = editor; + if (!selection) return false; + if (Range.isExpanded(selection)) return false; + + const previous = Editor.previous(editor); + + return previous && previous[0].type == 'break'; +} + +export default isCursorCollapsedAfterSoftBreak;