Skip to content

Commit beeec2a

Browse files
committed
feat: implement underline functionality to markdown editor
1 parent 0c7d327 commit beeec2a

File tree

7 files changed

+39
-0
lines changed

7 files changed

+39
-0
lines changed

packages/decap-cms-locales/src/en/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ const en = {
157157
markdown: {
158158
bold: 'Bold',
159159
italic: 'Italic',
160+
underline: 'Underline',
160161
strikethrough: 'Strikethrough',
161162
code: 'Code',
162163
link: 'Link',

packages/decap-cms-ui-default/src/Icon/images/_index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import iconScroll from './scroll.svg';
4343
import iconSearch from './search.svg';
4444
import iconSettings from './settings.svg';
4545
import iconStrikethrough from './strikethrough.svg';
46+
import iconUnderline from './underline.svg';
4647
import iconUser from './user.svg';
4748
import iconWorkflow from './workflow.svg';
4849
import iconWrite from './write.svg';
@@ -96,6 +97,7 @@ const images = {
9697
search: iconSearch,
9798
settings: iconSettings,
9899
strikethrough: iconStrikethrough,
100+
underline: iconUnderline,
99101
user: iconUser,
100102
workflow: iconWorkflow,
101103
write: iconWrite,
Lines changed: 1 addition & 0 deletions
Loading

packages/decap-cms-widget-markdown/src/MarkdownControl/Toolbar.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,16 @@ export default class Toolbar extends React.Component {
160160
disabled={disabled}
161161
/>
162162
)}
163+
{isVisible('underline') && (
164+
<ToolbarButton
165+
type="underline"
166+
label={t('editor.editorWidgets.markdown.underline')}
167+
icon="underline"
168+
onClick={this.handleMarkClick}
169+
isActive={hasMark('underline')}
170+
disabled={disabled}
171+
/>
172+
)}
163173
{isVisible('strikethrough') && (
164174
<ToolbarButton
165175
type="strikethrough"

packages/decap-cms-widget-markdown/src/MarkdownControl/renderers.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ function Italic(props) {
119119
return <em>{props.children}</em>;
120120
}
121121

122+
function Underline(props) {
123+
return <u>{props.children}</u>;
124+
}
125+
122126
function Strikethrough(props) {
123127
return <s>{props.children}</s>;
124128
}
@@ -267,6 +271,10 @@ export function Leaf({ attributes, children, leaf }) {
267271
children = <Italic>{children}</Italic>;
268272
}
269273

274+
if (leaf.underline) {
275+
children = <Underline>{children}</Underline>;
276+
}
277+
270278
if (leaf.delete) {
271279
children = <Strikethrough>{children}</Strikethrough>;
272280
}

packages/decap-cms-widget-markdown/src/schema.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export default {
88
enum: [
99
'bold',
1010
'italic',
11+
'underline',
1112
'strikethrough',
1213
'code',
1314
'link',

packages/decap-cms-widget-markdown/src/serializers/slateRemark.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const typeMap = {
4040
const markMap = {
4141
bold: 'strong',
4242
italic: 'emphasis',
43+
underline: 'underline',
4344
delete: 'delete',
4445
code: 'inlineCode',
4546
};
@@ -275,6 +276,21 @@ export default function slateToRemark(value, { voidCodeBlock }) {
275276
if (markType === 'code') {
276277
const node = markNodes[0];
277278
convertedNodes.push(u(markMap[markType], node.data, node.text));
279+
} else if (markType === 'underline') {
280+
// Handle underline as HTML since Markdown doesn't have native underline syntax
281+
const { leadingWhitespace, trailingWhitespace, centerNodes } =
282+
normalizeFlankingWhitespace(markNodes);
283+
const children = convertInlineAndTextChildren(centerNodes);
284+
const textContent = mdastToString({ type: 'paragraph', children });
285+
const htmlNode = u('html', `<u>${textContent}</u>`);
286+
287+
const normalizedNodes = [
288+
leadingWhitespace && createText(leadingWhitespace),
289+
htmlNode,
290+
trailingWhitespace && createText(trailingWhitespace),
291+
].filter(val => val);
292+
293+
convertedNodes.push(...normalizedNodes);
278294
} else if (!markType && markNodes.length === 1 && isNodeInline(nextNode)) {
279295
const node = markNodes[0];
280296
convertedNodes.push(convertInlineNode(node, convertInlineAndTextChildren(node.children)));

0 commit comments

Comments
 (0)