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.
@@ -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("*word* next");
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("***text***");
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: "*", suffix: "*" });
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.startsWith("*", i)) {
713
- const end = cleaned.indexOf("*", i + 1);
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);
@@ -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
- font-weight: 600 !important;
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
- border-radius: 3px !important;
1094
- font-family: "Fira Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;
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
+ }