testomatio-editor-blocks 0.4.52 → 0.4.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/editor/blocks/markdown.js +97 -36
- package/package/editor/blocks/stepField.d.ts +12 -0
- package/package/editor/blocks/stepField.js +37 -13
- package/package/editor/blocks/useAutoResize.d.ts +3 -4
- package/package/editor/blocks/useAutoResize.js +70 -26
- package/package/editor/customMarkdownConverter.js +88 -28
- package/package/styles.css +6 -0
- package/package.json +1 -1
- package/src/editor/blocks/markdown.ts +110 -40
- package/src/editor/blocks/stepField.tsx +48 -15
- package/src/editor/blocks/stepFieldFormatting.test.ts +62 -1
- package/src/editor/blocks/useAutoResize.ts +73 -30
- package/src/editor/customMarkdownConverter.test.ts +32 -11
- package/src/editor/customMarkdownConverter.ts +102 -29
- package/src/editor/markdownToBlocks.test.ts +39 -0
- package/src/editor/styles.css +6 -0
|
@@ -446,7 +446,7 @@ function serializeBlock(
|
|
|
446
446
|
const normalizedExpected = stripExpectedPrefix(expectedResult).trim();
|
|
447
447
|
if (normalizedExpected.length > 0) {
|
|
448
448
|
const expectedLines = normalizedExpected.split(/\r?\n/);
|
|
449
|
-
const label = "*Expected*";
|
|
449
|
+
const label = "*Expected result*";
|
|
450
450
|
expectedLines.forEach((expectedLine: string, index: number) => {
|
|
451
451
|
const trimmedLine = expectedLine.trim();
|
|
452
452
|
if (trimmedLine.length === 0) {
|
|
@@ -630,7 +630,41 @@ export function blocksToMarkdown(blocks: CustomEditorBlock[]): string {
|
|
|
630
630
|
}
|
|
631
631
|
|
|
632
632
|
function parseInlineMarkdown(text: string): EditorInline[] {
|
|
633
|
-
|
|
633
|
+
return parseInlineSegments(stripHtmlWrappers(text), {});
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function findItalicClose(
|
|
637
|
+
text: string,
|
|
638
|
+
start: number,
|
|
639
|
+
marker: "*" | "_",
|
|
640
|
+
): number {
|
|
641
|
+
let j = start;
|
|
642
|
+
while (j < text.length) {
|
|
643
|
+
const ch = text[j];
|
|
644
|
+
if (ch === "\\") {
|
|
645
|
+
j += 2;
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
if ((ch === "*" || ch === "_") && text[j + 1] === ch) {
|
|
649
|
+
const close = text.indexOf(ch + ch, j + 2);
|
|
650
|
+
if (close === -1) {
|
|
651
|
+
return -1;
|
|
652
|
+
}
|
|
653
|
+
j = close + 2;
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (ch === marker) {
|
|
657
|
+
return j;
|
|
658
|
+
}
|
|
659
|
+
j += 1;
|
|
660
|
+
}
|
|
661
|
+
return -1;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function parseInlineSegments(
|
|
665
|
+
cleaned: string,
|
|
666
|
+
outerStyles: Record<string, boolean>,
|
|
667
|
+
): EditorInline[] {
|
|
634
668
|
const result: EditorInline[] = [];
|
|
635
669
|
let buffer = "";
|
|
636
670
|
|
|
@@ -638,22 +672,53 @@ function parseInlineMarkdown(text: string): EditorInline[] {
|
|
|
638
672
|
if (buffer.length === 0) {
|
|
639
673
|
return;
|
|
640
674
|
}
|
|
641
|
-
result.push({
|
|
675
|
+
result.push({
|
|
676
|
+
type: "text",
|
|
677
|
+
text: unescapeMarkdown(buffer),
|
|
678
|
+
styles: { ...outerStyles } as EditorStyles,
|
|
679
|
+
});
|
|
642
680
|
buffer = "";
|
|
643
681
|
};
|
|
644
682
|
|
|
683
|
+
const wrap = (inner: string, add: Record<string, boolean>) => {
|
|
684
|
+
pushPlain();
|
|
685
|
+
const nested = parseInlineSegments(inner, { ...outerStyles, ...add });
|
|
686
|
+
result.push(...nested);
|
|
687
|
+
};
|
|
688
|
+
|
|
645
689
|
let i = 0;
|
|
646
690
|
while (i < cleaned.length) {
|
|
691
|
+
if (cleaned.startsWith("***", i)) {
|
|
692
|
+
const end = cleaned.indexOf("***", i + 3);
|
|
693
|
+
if (end !== -1) {
|
|
694
|
+
wrap(cleaned.slice(i + 3, end), { bold: true, italic: true });
|
|
695
|
+
i = end + 3;
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (cleaned.startsWith("___", i)) {
|
|
701
|
+
const end = cleaned.indexOf("___", i + 3);
|
|
702
|
+
if (end !== -1) {
|
|
703
|
+
wrap(cleaned.slice(i + 3, end), { bold: true, italic: true });
|
|
704
|
+
i = end + 3;
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
647
709
|
if (cleaned.startsWith("**", i)) {
|
|
648
710
|
const end = cleaned.indexOf("**", i + 2);
|
|
649
711
|
if (end !== -1) {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
712
|
+
wrap(cleaned.slice(i + 2, end), { bold: true });
|
|
713
|
+
i = end + 2;
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (cleaned.startsWith("__", i)) {
|
|
719
|
+
const end = cleaned.indexOf("__", i + 2);
|
|
720
|
+
if (end !== -1) {
|
|
721
|
+
wrap(cleaned.slice(i + 2, end), { bold: true });
|
|
657
722
|
i = end + 2;
|
|
658
723
|
continue;
|
|
659
724
|
}
|
|
@@ -662,13 +727,7 @@ function parseInlineMarkdown(text: string): EditorInline[] {
|
|
|
662
727
|
if (cleaned.startsWith("~~", i)) {
|
|
663
728
|
const end = cleaned.indexOf("~~", i + 2);
|
|
664
729
|
if (end !== -1) {
|
|
665
|
-
|
|
666
|
-
const inner = cleaned.slice(i + 2, end);
|
|
667
|
-
result.push({
|
|
668
|
-
type: "text",
|
|
669
|
-
text: unescapeMarkdown(inner),
|
|
670
|
-
styles: { strike: true },
|
|
671
|
-
});
|
|
730
|
+
wrap(cleaned.slice(i + 2, end), { strike: true });
|
|
672
731
|
i = end + 2;
|
|
673
732
|
continue;
|
|
674
733
|
}
|
|
@@ -682,7 +741,7 @@ function parseInlineMarkdown(text: string): EditorInline[] {
|
|
|
682
741
|
result.push({
|
|
683
742
|
type: "text",
|
|
684
743
|
text: unescapeMarkdown(inner),
|
|
685
|
-
styles: { code: true },
|
|
744
|
+
styles: { ...outerStyles, code: true } as EditorStyles,
|
|
686
745
|
});
|
|
687
746
|
i = end + 1;
|
|
688
747
|
continue;
|
|
@@ -697,7 +756,7 @@ function parseInlineMarkdown(text: string): EditorInline[] {
|
|
|
697
756
|
pushPlain();
|
|
698
757
|
const label = cleaned.slice(i + 1, endLabel);
|
|
699
758
|
const href = cleaned.slice(startLink + 1, endLink);
|
|
700
|
-
const parsedLabel =
|
|
759
|
+
const parsedLabel = parseInlineSegments(label, {});
|
|
701
760
|
// Ensure link content is never undefined - if empty, add empty text
|
|
702
761
|
const linkContent = parsedLabel.length > 0 ? parsedLabel : [{ type: "text", text: "", styles: {} }];
|
|
703
762
|
result.push({
|
|
@@ -711,16 +770,10 @@ function parseInlineMarkdown(text: string): EditorInline[] {
|
|
|
711
770
|
}
|
|
712
771
|
|
|
713
772
|
if (cleaned[i] === "*" || cleaned[i] === "_") {
|
|
714
|
-
const marker = cleaned[i];
|
|
715
|
-
const end = cleaned
|
|
773
|
+
const marker = cleaned[i] as "*" | "_";
|
|
774
|
+
const end = findItalicClose(cleaned, i + 1, marker);
|
|
716
775
|
if (end !== -1) {
|
|
717
|
-
|
|
718
|
-
const inner = cleaned.slice(i + 1, end);
|
|
719
|
-
result.push({
|
|
720
|
-
type: "text",
|
|
721
|
-
text: unescapeMarkdown(inner),
|
|
722
|
-
styles: { italic: true },
|
|
723
|
-
});
|
|
776
|
+
wrap(cleaned.slice(i + 1, end), { italic: true });
|
|
724
777
|
i = end + 1;
|
|
725
778
|
continue;
|
|
726
779
|
}
|
|
@@ -792,7 +845,27 @@ function parseList(
|
|
|
792
845
|
const trimmed = rawLine.trim();
|
|
793
846
|
|
|
794
847
|
if (!trimmed) {
|
|
795
|
-
|
|
848
|
+
// Peek at the next non-blank line. If it's another item of this list
|
|
849
|
+
// (same indent level and list type), treat the blank lines as loose-list
|
|
850
|
+
// separators and consume them. Otherwise leave the blank line for the
|
|
851
|
+
// outer loop so it can become an empty paragraph block.
|
|
852
|
+
let lookahead = index + 1;
|
|
853
|
+
while (lookahead < lines.length && !lines[lookahead].trim()) {
|
|
854
|
+
lookahead += 1;
|
|
855
|
+
}
|
|
856
|
+
if (lookahead >= lines.length) {
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
const nextLine = lines[lookahead];
|
|
860
|
+
const nextIndent = countIndent(nextLine);
|
|
861
|
+
if (nextIndent < indentLevel * 2) {
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
const nextType = detectListType(nextLine.trim());
|
|
865
|
+
if (nextType !== listType) {
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
index = lookahead;
|
|
796
869
|
continue;
|
|
797
870
|
}
|
|
798
871
|
|
|
@@ -130,4 +130,43 @@ describe("markdownToBlocks", () => {
|
|
|
130
130
|
children: [],
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
|
+
|
|
134
|
+
it("parses combined bold+italic using nested delimiters", () => {
|
|
135
|
+
const blocks = markdownToBlocks(
|
|
136
|
+
"The _**Username**_ and **_Password_** fields and ***both*** and ___both___.",
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
expect(blocks).toHaveLength(1);
|
|
140
|
+
expect(blocks[0]).toEqual({
|
|
141
|
+
type: "paragraph",
|
|
142
|
+
props: baseProps,
|
|
143
|
+
content: [
|
|
144
|
+
{ type: "text", text: "The ", styles: {} },
|
|
145
|
+
{ type: "text", text: "Username", styles: { italic: true, bold: true } },
|
|
146
|
+
{ type: "text", text: " and ", styles: {} },
|
|
147
|
+
{ type: "text", text: "Password", styles: { bold: true, italic: true } },
|
|
148
|
+
{ type: "text", text: " fields and ", styles: {} },
|
|
149
|
+
{ type: "text", text: "both", styles: { bold: true, italic: true } },
|
|
150
|
+
{ type: "text", text: " and ", styles: {} },
|
|
151
|
+
{ type: "text", text: "both", styles: { bold: true, italic: true } },
|
|
152
|
+
{ type: "text", text: ".", styles: {} },
|
|
153
|
+
],
|
|
154
|
+
children: [],
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("parses bold with nested italic keeping both styles", () => {
|
|
159
|
+
const blocks = markdownToBlocks("**foo _bar_ baz**");
|
|
160
|
+
|
|
161
|
+
expect(blocks[0]).toEqual({
|
|
162
|
+
type: "paragraph",
|
|
163
|
+
props: baseProps,
|
|
164
|
+
content: [
|
|
165
|
+
{ type: "text", text: "foo ", styles: { bold: true } },
|
|
166
|
+
{ type: "text", text: "bar", styles: { bold: true, italic: true } },
|
|
167
|
+
{ type: "text", text: " baz", styles: { bold: true } },
|
|
168
|
+
],
|
|
169
|
+
children: [],
|
|
170
|
+
});
|
|
171
|
+
});
|
|
133
172
|
});
|
package/src/editor/styles.css
CHANGED
|
@@ -1100,6 +1100,12 @@ html.dark .bn-step-image-preview__content {
|
|
|
1100
1100
|
color: rgb(146, 64, 14) !important;
|
|
1101
1101
|
}
|
|
1102
1102
|
|
|
1103
|
+
.bn-step-editor .overtype-wrapper .overtype-preview li.bullet-list .syntax-marker,
|
|
1104
|
+
.bn-step-editor .overtype-wrapper .overtype-preview li.ordered-list .syntax-marker {
|
|
1105
|
+
color: inherit !important;
|
|
1106
|
+
opacity: 1 !important;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1103
1109
|
.bn-step-custom-caret {
|
|
1104
1110
|
display: none;
|
|
1105
1111
|
position: absolute;
|