testomatio-editor-blocks 0.4.49 → 0.4.51
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 +1 -1
- package/package/editor/blocks/step.d.ts +1 -1
- package/package/editor/blocks/step.js +8 -18
- package/package/editor/blocks/stepField.d.ts +11 -0
- package/package/editor/blocks/stepField.js +228 -85
- package/package/editor/createMarkdownPasteHandler.js +18 -0
- package/package/editor/customMarkdownConverter.js +5 -7
- package/package/styles.css +16 -3
- package/package.json +1 -1
- package/src/editor/blocks/markdown.ts +1 -1
- package/src/editor/blocks/step.tsx +26 -42
- package/src/editor/blocks/stepField.tsx +267 -81
- package/src/editor/blocks/stepFieldFormatting.test.ts +44 -0
- package/src/editor/createMarkdownPasteHandler.ts +16 -0
- package/src/editor/customMarkdownConverter.test.ts +3 -3
- package/src/editor/customMarkdownConverter.ts +5 -7
- package/src/editor/styles.css +16 -3
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildFullMarkdown, type FormattingMeta, type LinkMeta } from "./stepField";
|
|
3
|
+
|
|
4
|
+
describe("buildFullMarkdown formatting combinations", () => {
|
|
5
|
+
const noLinks: LinkMeta[] = [];
|
|
6
|
+
|
|
7
|
+
it("applies bold and italic to the same range", () => {
|
|
8
|
+
const formatting: FormattingMeta[] = [
|
|
9
|
+
{ start: 0, end: 5, type: "bold" },
|
|
10
|
+
{ start: 0, end: 5, type: "italic" },
|
|
11
|
+
];
|
|
12
|
+
expect(buildFullMarkdown("hello", noLinks, formatting)).toBe("_**hello**_");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("preserves word-level bold when sentence-level bold is applied", () => {
|
|
16
|
+
// User bolds "adipiscing", then bolds entire sentence.
|
|
17
|
+
// The word-level bold should be merged into sentence-level bold,
|
|
18
|
+
// not create nested **...**adipiscing**...** markers.
|
|
19
|
+
const text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
|
|
20
|
+
const formatting: FormattingMeta[] = [
|
|
21
|
+
{ start: 0, end: text.length, type: "bold" },
|
|
22
|
+
];
|
|
23
|
+
expect(buildFullMarkdown(text, noLinks, formatting)).toBe(
|
|
24
|
+
`**${text}**`,
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("bold on word + italic on sentence produces correct markdown", () => {
|
|
29
|
+
const text = "hello world";
|
|
30
|
+
const formatting: FormattingMeta[] = [
|
|
31
|
+
{ start: 0, end: 5, type: "bold" },
|
|
32
|
+
{ start: 0, end: 11, type: "italic" },
|
|
33
|
+
];
|
|
34
|
+
expect(buildFullMarkdown(text, noLinks, formatting)).toBe("_**hello** world_");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("code formatting removes bold and italic", () => {
|
|
38
|
+
// When code is applied, bold/italic should not appear
|
|
39
|
+
const formatting: FormattingMeta[] = [
|
|
40
|
+
{ start: 0, end: 5, type: "code" },
|
|
41
|
+
];
|
|
42
|
+
expect(buildFullMarkdown("hello", noLinks, formatting)).toBe("`hello`");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -10,6 +10,18 @@ type PasteHandlerContext = {
|
|
|
10
10
|
}) => boolean | undefined;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
const BLOCK_MARKDOWN_PREFIX = /^(\s*)(#{1,6}\s|[-*+]\s|\d+[.)]\s|>\s|```|~~~|\||!\[)/;
|
|
14
|
+
|
|
15
|
+
function isInlineOnlyPaste(plainText: string, parsedBlocks: CustomPartialBlock[]): boolean {
|
|
16
|
+
if (parsedBlocks.length !== 1) return false;
|
|
17
|
+
const [block] = parsedBlocks;
|
|
18
|
+
if (block.type !== "paragraph") return false;
|
|
19
|
+
if (block.children && block.children.length > 0) return false;
|
|
20
|
+
if (/\r?\n/.test(plainText)) return false;
|
|
21
|
+
if (BLOCK_MARKDOWN_PREFIX.test(plainText)) return false;
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
export function createMarkdownPasteHandler(
|
|
14
26
|
converter: (markdown: string) => CustomPartialBlock[],
|
|
15
27
|
) {
|
|
@@ -34,6 +46,10 @@ export function createMarkdownPasteHandler(
|
|
|
34
46
|
const parsedBlocks = converter(plainText);
|
|
35
47
|
if (parsedBlocks.length === 0) return defaultPasteHandler();
|
|
36
48
|
|
|
49
|
+
if (isInlineOnlyPaste(plainText, parsedBlocks)) {
|
|
50
|
+
return defaultPasteHandler({ plainTextAsMarkdown: false });
|
|
51
|
+
}
|
|
52
|
+
|
|
37
53
|
const selection = editor.getSelection();
|
|
38
54
|
const selectedIds = selection?.blocks
|
|
39
55
|
?.map((block: any) => block.id)
|
|
@@ -43,7 +43,7 @@ describe("blocksToMarkdown", () => {
|
|
|
43
43
|
},
|
|
44
44
|
];
|
|
45
45
|
|
|
46
|
-
expect(blocksToMarkdown(blocks)).toBe("Hello **world
|
|
46
|
+
expect(blocksToMarkdown(blocks)).toBe("Hello **world**_!_");
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
it("places bold markers outside leading/trailing spaces", () => {
|
|
@@ -76,7 +76,7 @@ describe("blocksToMarkdown", () => {
|
|
|
76
76
|
children: [],
|
|
77
77
|
},
|
|
78
78
|
];
|
|
79
|
-
expect(blocksToMarkdown(blocks)).toBe("
|
|
79
|
+
expect(blocksToMarkdown(blocks)).toBe("_word_ next");
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
it("places code backticks outside leading/trailing spaces", () => {
|
|
@@ -301,7 +301,7 @@ describe("blocksToMarkdown", () => {
|
|
|
301
301
|
];
|
|
302
302
|
|
|
303
303
|
const markdown = blocksToMarkdown(blocks);
|
|
304
|
-
expect(markdown).toBe("
|
|
304
|
+
expect(markdown).toBe("_**text**_");
|
|
305
305
|
});
|
|
306
306
|
|
|
307
307
|
it("keeps inline formatting inside step fields", () => {
|
|
@@ -152,7 +152,7 @@ function applyTextStyles(text: string, styles: EditorStyles | undefined): string
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
if (styles.italic) {
|
|
155
|
-
wrappers.push({ prefix: "
|
|
155
|
+
wrappers.push({ prefix: "_", suffix: "_" });
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
if (styles.strike) {
|
|
@@ -620,10 +620,7 @@ function serializeBlocks(blocks: CustomEditorBlock[], ctx: MarkdownContext): str
|
|
|
620
620
|
|
|
621
621
|
export function blocksToMarkdown(blocks: CustomEditorBlock[]): string {
|
|
622
622
|
const lines = serializeBlocks(blocks, { listDepth: 0, insideQuote: false });
|
|
623
|
-
const cleaned = lines
|
|
624
|
-
.join("\n")
|
|
625
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
626
|
-
.trimEnd();
|
|
623
|
+
const cleaned = lines.join("\n").trimEnd();
|
|
627
624
|
|
|
628
625
|
return cleaned;
|
|
629
626
|
}
|
|
@@ -709,8 +706,9 @@ function parseInlineMarkdown(text: string): EditorInline[] {
|
|
|
709
706
|
}
|
|
710
707
|
}
|
|
711
708
|
|
|
712
|
-
if (cleaned
|
|
713
|
-
const
|
|
709
|
+
if (cleaned[i] === "*" || cleaned[i] === "_") {
|
|
710
|
+
const marker = cleaned[i];
|
|
711
|
+
const end = cleaned.indexOf(marker, i + 1);
|
|
714
712
|
if (end !== -1) {
|
|
715
713
|
pushPlain();
|
|
716
714
|
const inner = cleaned.slice(i + 1, end);
|
package/src/editor/styles.css
CHANGED
|
@@ -947,6 +947,10 @@ html.dark .bn-step-image-preview__content {
|
|
|
947
947
|
color: var(--step-input-border-focus);
|
|
948
948
|
}
|
|
949
949
|
|
|
950
|
+
.bn-container {
|
|
951
|
+
overflow-x: clip;
|
|
952
|
+
}
|
|
953
|
+
|
|
950
954
|
[data-tooltip] {
|
|
951
955
|
position: relative;
|
|
952
956
|
}
|
|
@@ -1079,7 +1083,8 @@ html.dark .bn-step-image-preview__content {
|
|
|
1079
1083
|
}
|
|
1080
1084
|
|
|
1081
1085
|
.bn-step-editor .overtype-wrapper .overtype-preview strong.step-preview-bold {
|
|
1082
|
-
|
|
1086
|
+
-webkit-text-stroke: 0.5px currentColor;
|
|
1087
|
+
font-weight: inherit !important;
|
|
1083
1088
|
color: inherit !important;
|
|
1084
1089
|
}
|
|
1085
1090
|
|
|
@@ -1090,8 +1095,8 @@ html.dark .bn-step-image-preview__content {
|
|
|
1090
1095
|
|
|
1091
1096
|
.bn-step-editor .overtype-wrapper .overtype-preview code.step-preview-code {
|
|
1092
1097
|
background-color: transparent !important;
|
|
1093
|
-
|
|
1094
|
-
font-
|
|
1098
|
+
font-family: inherit !important;
|
|
1099
|
+
font-size: inherit !important;
|
|
1095
1100
|
color: rgb(146, 64, 14) !important;
|
|
1096
1101
|
}
|
|
1097
1102
|
|
|
@@ -1356,3 +1361,11 @@ html.dark .bn-step-image-preview__content {
|
|
|
1356
1361
|
.bn-testcase--draft {
|
|
1357
1362
|
--status-color: var(--status-default);
|
|
1358
1363
|
}
|
|
1364
|
+
|
|
1365
|
+
/* Prevent unnecessary horizontal scrollbar on BlockNote tables.
|
|
1366
|
+
ProseMirror sets overflow-x: auto on .tableWrapper, but the
|
|
1367
|
+
table-widgets-container extends slightly past the wrapper edge,
|
|
1368
|
+
triggering a scrollbar even when table content fits. */
|
|
1369
|
+
.bn-editor [data-content-type="table"] .tableWrapper {
|
|
1370
|
+
overflow-x: hidden;
|
|
1371
|
+
}
|