Skip to content

Commit 23a9e88

Browse files
committed
style: enhance text formatting options in schema and markdown serializer
- Added underline and strike-through support in the schema for improved text styling. - Introduced highlight and textStyle attributes to allow for customizable text formatting. - Updated markdown serializer to handle underline and textStyle, including background color for highlights.
1 parent f6ad75f commit 23a9e88

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

packages/utils/src/editor/schema.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,30 @@ export const schema = new Schema({
273273
},
274274
} as MarkSpec,
275275

276+
underline: {
277+
parseDOM: [
278+
{ tag: 'u' },
279+
{ style: 'text-decoration=underline' },
280+
{ style: 'text-decoration-line=underline' },
281+
],
282+
toDOM() {
283+
return ['u', 0];
284+
},
285+
},
286+
287+
strike: {
288+
parseDOM: [
289+
{ tag: 's' },
290+
{ tag: 'strike' },
291+
{ tag: 'del' },
292+
{ style: 'text-decoration=line-through' },
293+
{ style: 'text-decoration-line=line-through' },
294+
],
295+
toDOM() {
296+
return ['s', 0];
297+
},
298+
},
299+
276300
link: {
277301
attrs: {
278302
href: {},
@@ -301,5 +325,81 @@ export const schema = new Schema({
301325
return ['code'];
302326
},
303327
},
328+
329+
highlight: {
330+
attrs: {
331+
color: { default: null },
332+
},
333+
parseDOM: [
334+
{
335+
tag: 'mark',
336+
getAttrs: (node) => {
337+
const dom = node as HTMLElement;
338+
return {
339+
color: dom.getAttribute('data-color') || dom.style.backgroundColor,
340+
};
341+
},
342+
},
343+
],
344+
toDOM(node) {
345+
const attrs: Record<string, string> = {};
346+
if (node.attrs.color) {
347+
attrs['data-color'] = node.attrs.color;
348+
attrs.style = `background-color: ${node.attrs.color}; color: inherit`;
349+
}
350+
return ['mark', attrs, 0];
351+
},
352+
},
353+
354+
textStyle: {
355+
attrs: {
356+
color: { default: null },
357+
backgroundColor: { default: null },
358+
fontSize: { default: null },
359+
fontFamily: { default: null },
360+
fontWeight: { default: null },
361+
textDecoration: { default: null },
362+
},
363+
parseDOM: [
364+
{
365+
tag: 'span[style]',
366+
getAttrs: (node) => {
367+
const dom = node as HTMLElement;
368+
return {
369+
color: dom.style.color,
370+
backgroundColor: dom.style.backgroundColor,
371+
fontSize: dom.style.fontSize,
372+
fontFamily: dom.style.fontFamily,
373+
fontWeight: dom.style.fontWeight,
374+
textDecoration: dom.style.textDecoration,
375+
};
376+
},
377+
},
378+
],
379+
toDOM(node) {
380+
const attrs: Record<string, string> = { style: '' };
381+
382+
if (node.attrs.color) {
383+
attrs.style += `color: ${node.attrs.color};`;
384+
}
385+
if (node.attrs.backgroundColor) {
386+
attrs.style += `background-color: ${node.attrs.backgroundColor}; color: inherit;`;
387+
}
388+
if (node.attrs.fontSize) {
389+
attrs.style += `font-size: ${node.attrs.fontSize};`;
390+
}
391+
if (node.attrs.fontFamily) {
392+
attrs.style += `font-family: ${node.attrs.fontFamily};`;
393+
}
394+
if (node.attrs.fontWeight) {
395+
attrs.style += `font-weight: ${node.attrs.fontWeight};`;
396+
}
397+
if (node.attrs.textDecoration) {
398+
attrs.style += `text-decoration: ${node.attrs.textDecoration};`;
399+
}
400+
401+
return ['span', attrs, 0];
402+
},
403+
},
304404
},
305405
});

packages/utils/src/editor/to_markdown.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ export const defaultMarkdownSerializer = new MarkdownSerializer(
230230
mixable: true,
231231
expelEnclosingWhitespace: true,
232232
},
233+
underline: {
234+
open: '__',
235+
close: '__',
236+
mixable: true,
237+
expelEnclosingWhitespace: true,
238+
},
233239
link: {
234240
open(state, mark, parent, index) {
235241
state.inAutolink = isPlainURL(mark, parent, index);
@@ -264,6 +270,26 @@ export const defaultMarkdownSerializer = new MarkdownSerializer(
264270
mixable: true,
265271
expelEnclosingWhitespace: true,
266272
},
273+
textStyle: {
274+
open(_state, mark, _parent, _index) {
275+
// Check if there's backgroundColor and treat it as highlight
276+
if (mark.attrs.backgroundColor) {
277+
return '==';
278+
}
279+
// For other text styles, don't add any markdown markers
280+
return '';
281+
},
282+
close(_state, mark, _parent, _index) {
283+
// Close highlight syntax if there's backgroundColor
284+
if (mark.attrs.backgroundColor) {
285+
return '==';
286+
}
287+
// For other text styles, don't add any markdown markers
288+
return '';
289+
},
290+
mixable: true,
291+
expelEnclosingWhitespace: true,
292+
},
267293
},
268294
);
269295

0 commit comments

Comments
 (0)