Skip to content

Commit 7e6f6af

Browse files
authored
Merge pull request #5349 from BookStackApp/lexical_reorg
Lexical: Merge of custom nodes & re-organisation of codebase
2 parents 5164375 + d00cf6e commit 7e6f6af

File tree

92 files changed

+1319
-2894
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1319
-2894
lines changed

resources/js/wysiwyg/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {$getSelection, createEditor, CreateEditorArgs, isCurrentlyReadOnlyMode, LexicalEditor} from 'lexical';
1+
import {$getSelection, createEditor, CreateEditorArgs, LexicalEditor} from 'lexical';
22
import {createEmptyHistoryState, registerHistory} from '@lexical/history';
33
import {registerRichText} from '@lexical/rich-text';
44
import {mergeRegister} from '@lexical/utils';

resources/js/wysiwyg/lexical/core/LexicalEvents.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,6 @@ function onSelectionChange(
355355
lastNode instanceof ParagraphNode &&
356356
lastNode.getChildrenSize() === 0
357357
) {
358-
selection.format = lastNode.getTextFormat();
359358
selection.style = lastNode.getTextStyle();
360359
} else {
361360
selection.format = 0;
@@ -578,7 +577,6 @@ function onBeforeInput(event: InputEvent, editor: LexicalEditor): void {
578577
if ($isRangeSelection(selection)) {
579578
const anchorNode = selection.anchor.getNode();
580579
anchorNode.markDirty();
581-
selection.format = anchorNode.getFormat();
582580
invariant(
583581
$isTextNode(anchorNode),
584582
'Anchor node must be a TextNode',
@@ -912,7 +910,6 @@ function onCompositionStart(
912910
// need to invoke the empty space heuristic below.
913911
anchor.type === 'element' ||
914912
!selection.isCollapsed() ||
915-
node.getFormat() !== selection.format ||
916913
($isTextNode(node) && node.getStyle() !== selection.style)
917914
) {
918915
// We insert a zero width character, ready for the composition

resources/js/wysiwyg/lexical/core/LexicalMutations.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
$getSelection,
1717
$isDecoratorNode,
1818
$isElementNode,
19-
$isRangeSelection,
2019
$isTextNode,
2120
$setSelection,
2221
} from '.';
@@ -96,15 +95,6 @@ function shouldUpdateTextNodeFromMutation(
9695
targetDOM: Node,
9796
targetNode: TextNode,
9897
): boolean {
99-
if ($isRangeSelection(selection)) {
100-
const anchorNode = selection.anchor.getNode();
101-
if (
102-
anchorNode.is(targetNode) &&
103-
selection.format !== anchorNode.getFormat()
104-
) {
105-
return false;
106-
}
107-
}
10898
return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached();
10999
}
110100

resources/js/wysiwyg/lexical/core/LexicalReconciler.ts

Lines changed: 6 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import type {NodeKey, NodeMap} from './LexicalNode';
1717
import type {ElementNode} from './nodes/LexicalElementNode';
1818

1919
import invariant from 'lexical/shared/invariant';
20-
import normalizeClassNames from 'lexical/shared/normalizeClassNames';
2120

2221
import {
2322
$isDecoratorNode,
@@ -30,12 +29,12 @@ import {
3029
import {
3130
DOUBLE_LINE_BREAK,
3231
FULL_RECONCILE,
33-
IS_ALIGN_CENTER,
34-
IS_ALIGN_END,
35-
IS_ALIGN_JUSTIFY,
36-
IS_ALIGN_LEFT,
37-
IS_ALIGN_RIGHT,
38-
IS_ALIGN_START,
32+
33+
34+
35+
36+
37+
3938
} from './LexicalConstants';
4039
import {EditorState} from './LexicalEditorState';
4140
import {
@@ -117,51 +116,6 @@ function setTextAlign(domStyle: CSSStyleDeclaration, value: string): void {
117116
domStyle.setProperty('text-align', value);
118117
}
119118

120-
const DEFAULT_INDENT_VALUE = '40px';
121-
122-
function setElementIndent(dom: HTMLElement, indent: number): void {
123-
const indentClassName = activeEditorConfig.theme.indent;
124-
125-
if (typeof indentClassName === 'string') {
126-
const elementHasClassName = dom.classList.contains(indentClassName);
127-
128-
if (indent > 0 && !elementHasClassName) {
129-
dom.classList.add(indentClassName);
130-
} else if (indent < 1 && elementHasClassName) {
131-
dom.classList.remove(indentClassName);
132-
}
133-
}
134-
135-
const indentationBaseValue =
136-
getComputedStyle(dom).getPropertyValue('--lexical-indent-base-value') ||
137-
DEFAULT_INDENT_VALUE;
138-
139-
dom.style.setProperty(
140-
'padding-inline-start',
141-
indent === 0 ? '' : `calc(${indent} * ${indentationBaseValue})`,
142-
);
143-
}
144-
145-
function setElementFormat(dom: HTMLElement, format: number): void {
146-
const domStyle = dom.style;
147-
148-
if (format === 0) {
149-
setTextAlign(domStyle, '');
150-
} else if (format === IS_ALIGN_LEFT) {
151-
setTextAlign(domStyle, 'left');
152-
} else if (format === IS_ALIGN_CENTER) {
153-
setTextAlign(domStyle, 'center');
154-
} else if (format === IS_ALIGN_RIGHT) {
155-
setTextAlign(domStyle, 'right');
156-
} else if (format === IS_ALIGN_JUSTIFY) {
157-
setTextAlign(domStyle, 'justify');
158-
} else if (format === IS_ALIGN_START) {
159-
setTextAlign(domStyle, 'start');
160-
} else if (format === IS_ALIGN_END) {
161-
setTextAlign(domStyle, 'end');
162-
}
163-
}
164-
165119
function $createNode(
166120
key: NodeKey,
167121
parentDOM: null | HTMLElement,
@@ -185,22 +139,14 @@ function $createNode(
185139
}
186140

187141
if ($isElementNode(node)) {
188-
const indent = node.__indent;
189142
const childrenSize = node.__size;
190143

191-
if (indent !== 0) {
192-
setElementIndent(dom, indent);
193-
}
194144
if (childrenSize !== 0) {
195145
const endIndex = childrenSize - 1;
196146
const children = createChildrenArray(node, activeNextNodeMap);
197147
$createChildren(children, node, 0, endIndex, dom, null);
198148
}
199-
const format = node.__format;
200149

201-
if (format !== 0) {
202-
setElementFormat(dom, format);
203-
}
204150
if (!node.isInline()) {
205151
reconcileElementTerminatingLineBreak(null, node, dom);
206152
}
@@ -349,10 +295,8 @@ function reconcileParagraphFormat(element: ElementNode): void {
349295
if (
350296
$isParagraphNode(element) &&
351297
subTreeTextFormat != null &&
352-
subTreeTextFormat !== element.__textFormat &&
353298
!activeEditorStateReadOnly
354299
) {
355-
element.setTextFormat(subTreeTextFormat);
356300
element.setTextStyle(subTreeTextStyle);
357301
}
358302
}
@@ -563,17 +507,6 @@ function $reconcileNode(
563507

564508
if ($isElementNode(prevNode) && $isElementNode(nextNode)) {
565509
// Reconcile element children
566-
const nextIndent = nextNode.__indent;
567-
568-
if (nextIndent !== prevNode.__indent) {
569-
setElementIndent(dom, nextIndent);
570-
}
571-
572-
const nextFormat = nextNode.__format;
573-
574-
if (nextFormat !== prevNode.__format) {
575-
setElementFormat(dom, nextFormat);
576-
}
577510
if (isDirty) {
578511
$reconcileChildrenWithDirection(prevNode, nextNode, dom);
579512
if (!$isRootNode(nextNode) && !nextNode.isInline()) {

resources/js/wysiwyg/lexical/core/__tests__/unit/HTMLCopyAndPaste.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ describe('HTMLCopyAndPaste tests', () => {
8282
pastedHTML: ` <span>123<div>456</div></span>`,
8383
},
8484
{
85-
expectedHTML: `<ul><li role="checkbox" tabindex="-1" aria-checked="true" value="1"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">done</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">todo</span></li><li value="3"><ul><li role="checkbox" tabindex="-1" aria-checked="true" value="1"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">done</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">todo</span></li></ul></li><li role="checkbox" tabindex="-1" aria-checked="false" value="3"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">todo</span></li></ul>`,
85+
expectedHTML: `<ul><li class="task-list-item" checked="checked" value="1"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">done</span></li><li class="task-list-item" value="2"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">todo</span></li><li value="3" style="list-style: none;"><ul><li class="task-list-item" checked="checked" value="1"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">done</span></li><li class="task-list-item" value="2"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">todo</span></li></ul></li><li class="task-list-item" value="3"><span style="color: rgb(0, 0, 0);" data-lexical-text="true">todo</span></li></ul>`,
8686
name: 'google doc checklist',
8787
pastedHTML: `<meta charset='utf-8'><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-1980f960-7fff-f4df-4ba3-26c6e1508542"><ul style="margin-top:0;margin-bottom:0;padding-inline-start:28px;"><li role="checkbox" aria-checked="true" style="list-style-type:none;font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:line-through;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;" aria-level="1"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAABbElEQVR4Ae3bsU4CYRDEcRsxodZE8Q0BbS258l5MwESJNL6HOfrPKdhyxeBcwk5mkn9F98sGIOSuPM/zPM/zPI+xG/SEtuiAWpEOaIOWaDIWziP6RK14OzSjX44ITvTBvqRn1MRaMIHeBIE2TKBBEGhgArWkKmtJBjKQgQxkIANd/Aw0NVC+O7RHvYFynHasN1COE/UGynGiXgOIjxOtdIH4OGJAfBwxID6OGBAfRwiIjyMARMCpCjRF5+72Dzhd5R+rHfpC92NeTlWgLl5PkQg4RYBynBSJgFMGKMNJkQg4lYFeUDuFRMCpBXQOEgGnDtA/kPg4xT7m2y/tCd9zKgOdviTC5RQEIiAFjh4QASlw9IAISIEjCURAWvmf1UDKcQwUSDmOgWLdMcxA7BnIQAYykIEM5EcRvplAW0GgNRNoKQg0ZwJN0E4I5x1dI+pmgSSA84BG2QQt0LrYG/eAXtGccjme53me53me9wPjPWZWjhktAQAAAABJRU5ErkJggg==" width="18.4px" height="18.4px" alt="checked" aria-roledescription="checkbox" style="margin-right:3px;" /><p style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;display:inline-block;vertical-align:top;margin-top:0;" role="presentation"><span style="font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:line-through;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">done</span></p></li><li role="checkbox" aria-checked="false" style="list-style-type:none;font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;" aria-level="1"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAA1ElEQVR4Ae3bMQ4BURSFYY2xBuwQ7BIkTGxFRj9Oo9RdkXn5TvL3L19u+2ZmZmZmZhVbpH26pFcaJ9IrndMudb/CWadHGiden1bll9MIzqd79SUd0thY20qga4NA50qgoUGgoRJo/NL/V/N+QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEyFeEZyXQpUGgUyXQrkGgTSVQl/qGcG5pnkq3Sn0jOMv0k3Vpm05pmNjfsGPalFyOmZmZmdkbSS9cKbtzhxMAAAAASUVORK5CYII=" width="18.4px" height="18.4px" alt="unchecked" aria-roledescription="checkbox" style="margin-right:3px;" /><p style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;display:inline-block;vertical-align:top;margin-top:0;" role="presentation"><span style="font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">todo</span></p></li><ul style="margin-top:0;margin-bottom:0;padding-inline-start:28px;"><li role="checkbox" aria-checked="true" style="list-style-type:none;font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:line-through;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;" aria-level="2"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAABbElEQVR4Ae3bsU4CYRDEcRsxodZE8Q0BbS258l5MwESJNL6HOfrPKdhyxeBcwk5mkn9F98sGIOSuPM/zPM/zPI+xG/SEtuiAWpEOaIOWaDIWziP6RK14OzSjX44ITvTBvqRn1MRaMIHeBIE2TKBBEGhgArWkKmtJBjKQgQxkIANd/Aw0NVC+O7RHvYFynHasN1COE/UGynGiXgOIjxOtdIH4OGJAfBwxID6OGBAfRwiIjyMARMCpCjRF5+72Dzhd5R+rHfpC92NeTlWgLl5PkQg4RYBynBSJgFMGKMNJkQg4lYFeUDuFRMCpBXQOEgGnDtA/kPg4xT7m2y/tCd9zKgOdviTC5RQEIiAFjh4QASlw9IAISIEjCURAWvmf1UDKcQwUSDmOgWLdMcxA7BnIQAYykIEM5EcRvplAW0GgNRNoKQg0ZwJN0E4I5x1dI+pmgSSA84BG2QQt0LrYG/eAXtGccjme53me53me9wPjPWZWjhktAQAAAABJRU5ErkJggg==" width="18.4px" height="18.4px" alt="checked" aria-roledescription="checkbox" style="margin-right:3px;" /><p style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;display:inline-block;vertical-align:top;margin-top:0;" role="presentation"><span style="font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:line-through;-webkit-text-decoration-skip:none;text-decoration-skip-ink:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">done</span></p></li><li role="checkbox" aria-checked="false" style="list-style-type:none;font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;" aria-level="2"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAA1ElEQVR4Ae3bMQ4BURSFYY2xBuwQ7BIkTGxFRj9Oo9RdkXn5TvL3L19u+2ZmZmZmZhVbpH26pFcaJ9IrndMudb/CWadHGiden1bll9MIzqd79SUd0thY20qga4NA50qgoUGgoRJo/NL/V/N+QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEyFeEZyXQpUGgUyXQrkGgTSVQl/qGcG5pnkq3Sn0jOMv0k3Vpm05pmNjfsGPalFyOmZmZmdkbSS9cKbtzhxMAAAAASUVORK5CYII=" width="18.4px" height="18.4px" alt="unchecked" aria-roledescription="checkbox" style="margin-right:3px;" /><p style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;display:inline-block;vertical-align:top;margin-top:0;" role="presentation"><span style="font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">todo</span></p></li></ul><li role="checkbox" aria-checked="false" style="list-style-type:none;font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;" aria-level="1"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAA1ElEQVR4Ae3bMQ4BURSFYY2xBuwQ7BIkTGxFRj9Oo9RdkXn5TvL3L19u+2ZmZmZmZhVbpH26pFcaJ9IrndMudb/CWadHGiden1bll9MIzqd79SUd0thY20qga4NA50qgoUGgoRJo/NL/V/N+QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEyFeEZyXQpUGgUyXQrkGgTSVQl/qGcG5pnkq3Sn0jOMv0k3Vpm05pmNjfsGPalFyOmZmZmdkbSS9cKbtzhxMAAAAASUVORK5CYII=" width="18.4px" height="18.4px" alt="unchecked" aria-roledescription="checkbox" style="margin-right:3px;" /><p style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;display:inline-block;vertical-align:top;margin-top:0;" role="presentation"><span style="font-size:11.5pt;font-family:'Optimistic Text',sans-serif;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">todo</span></p></li></ul></b>`,
8888
},
8989
{
90-
expectedHTML: `<p style="text-align: start;"><span data-lexical-text="true">checklist</span></p><ul><li role="checkbox" tabindex="-1" aria-checked="true" value="1" style="text-align: start;"><span data-lexical-text="true">done</span></li><li role="checkbox" tabindex="-1" aria-checked="false" value="2" style="text-align: start;"><span data-lexical-text="true">todo</span></li></ul>`,
90+
expectedHTML: `<p><span data-lexical-text="true">checklist</span></p><ul><li class="task-list-item" checked="checked" value="1"><span data-lexical-text="true">done</span></li><li class="task-list-item" value="2"><span data-lexical-text="true">todo</span></li></ul>`,
9191
name: 'github checklist',
9292
pastedHTML: `<meta charset='utf-8'><p dir="auto" style="box-sizing: border-box; margin-top: 0px !important; margin-bottom: 16px; color: rgb(31, 35, 40); font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, &quot;Noto Sans&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">checklist</p><ul class="contains-task-list" style="box-sizing: border-box; padding: 0px; margin-top: 0px; margin-bottom: 0px !important; position: relative; color: rgb(31, 35, 40); font-family: -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, &quot;Noto Sans&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><li class="task-list-item enabled" style="box-sizing: border-box; list-style-type: none; padding: 2px 15px 2px 42px; margin-right: -15px; margin-left: -15px; line-height: 1.5; border: 0px;"><span class="handle" style="box-sizing: border-box; display: block; float: left; width: 20px; padding: 2px 0px 0px 2px; margin-left: -43px; opacity: 0;"><svg class="drag-handle" aria-hidden="true" width="16" height="16"><path d="M10 13a1 1 0 100-2 1 1 0 000 2zm-4 0a1 1 0 100-2 1 1 0 000 2zm1-5a1 1 0 11-2 0 1 1 0 012 0zm3 1a1 1 0 100-2 1 1 0 000 2zm1-5a1 1 0 11-2 0 1 1 0 012 0zM6 5a1 1 0 100-2 1 1 0 000 2z"></path></svg></span><input type="checkbox" id="" class="task-list-item-checkbox" checked="" style="box-sizing: border-box; font: inherit; margin: 0px 0.2em 0.25em -1.4em; overflow: visible; padding: 0px; vertical-align: middle;"><span></span>done</li><li class="task-list-item enabled" style="box-sizing: border-box; list-style-type: none; margin-top: 0px; padding: 2px 15px 2px 42px; margin-right: -15px; margin-left: -15px; line-height: 1.5; border: 0px;"><span class="handle" style="box-sizing: border-box; display: block; float: left; width: 20px; padding: 2px 0px 0px 2px; margin-left: -43px; opacity: 0;"><svg class="drag-handle" aria-hidden="true" width="16" height="16"><path d="M10 13a1 1 0 100-2 1 1 0 000 2zm-4 0a1 1 0 100-2 1 1 0 000 2zm1-5a1 1 0 11-2 0 1 1 0 012 0zm3 1a1 1 0 100-2 1 1 0 000 2zm1-5a1 1 0 11-2 0 1 1 0 012 0zM6 5a1 1 0 100-2 1 1 0 000 2z"></path></svg></span><input type="checkbox" id="" class="task-list-item-checkbox" style="box-sizing: border-box; font: inherit; margin: 0px 0.2em 0.25em -1.4em; overflow: visible; padding: 0px; vertical-align: middle;"><span></span>todo</li></ul>`,
9393
},

0 commit comments

Comments
 (0)