testomatio-editor-blocks 0.4.25 → 0.4.26

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.
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Returns true when a normalised (lowercased, trailing-punctuation-stripped)
3
+ * heading text looks like a "Steps" heading.
4
+ * Accepted forms: steps, step, step(s).
5
+ */
6
+ export declare function isStepsHeading(text: string): boolean;
1
7
  export declare const isEmptyParagraph: (b: any) => boolean;
2
8
  /**
3
9
  * Check whether a step or snippet can be inserted at / after the given block.
@@ -43,6 +43,14 @@ const writeStepViewMode = (mode) => {
43
43
  //
44
44
  }
45
45
  };
46
+ /**
47
+ * Returns true when a normalised (lowercased, trailing-punctuation-stripped)
48
+ * heading text looks like a "Steps" heading.
49
+ * Accepted forms: steps, step, step(s).
50
+ */
51
+ export function isStepsHeading(text) {
52
+ return /^step(s|\(s\))?$/.test(text);
53
+ }
46
54
  export const isEmptyParagraph = (b) => b.type === "paragraph" &&
47
55
  (!Array.isArray(b.content) ||
48
56
  b.content.length === 0 ||
@@ -71,7 +79,7 @@ export function canInsertStepOrSnippet(editor, referenceBlockId) {
71
79
  .trim()
72
80
  .toLowerCase()
73
81
  .replace(/[:\-–—]$/, "");
74
- return text === "steps";
82
+ return isStepsHeading(text);
75
83
  }
76
84
  return false;
77
85
  }
@@ -148,7 +156,7 @@ export const stepBlock = createReactBlockSpec({
148
156
  .trim()
149
157
  .toLowerCase()
150
158
  .replace(/[:\-–—]$/, "");
151
- return text === "steps";
159
+ return isStepsHeading(text);
152
160
  }
153
161
  return false;
154
162
  }
@@ -1,4 +1,5 @@
1
1
  import { isLinkInlineContent, isStyledTextInlineContent, } from "@blocknote/core";
2
+ import { isStepsHeading } from "./blocks/step";
2
3
  const BASE_BLOCK_PROPS = {
3
4
  textAlignment: "left",
4
5
  textColor: "default",
@@ -1183,7 +1184,7 @@ export function markdownToBlocks(markdown) {
1183
1184
  const headingLevel = (_b = (_a = headingBlock.props) === null || _a === void 0 ? void 0 : _a.level) !== null && _b !== void 0 ? _b : 3;
1184
1185
  const headingText = inlineContentToPlainText(headingBlock.content);
1185
1186
  const normalizedHeading = headingText.trim().toLowerCase();
1186
- if (normalizedHeading.replace(/[:\-–—]$/, "") === "steps") {
1187
+ if (isStepsHeading(normalizedHeading.replace(/[:\-–—]$/, ""))) {
1187
1188
  stepsHeadingLevel = headingLevel;
1188
1189
  }
1189
1190
  else if (stepsHeadingLevel !== null &&
@@ -1,5 +1,5 @@
1
1
  export { customSchema, type CustomSchema, type CustomBlock, type CustomEditor, } from "./editor/customSchema";
2
- export { stepBlock, canInsertStepOrSnippet } from "./editor/blocks/step";
2
+ export { stepBlock, canInsertStepOrSnippet, isStepsHeading } from "./editor/blocks/step";
3
3
  export { snippetBlock } from "./editor/blocks/snippet";
4
4
  export { markdownToHtml, htmlToMarkdown } from "./editor/blocks/markdown";
5
5
  export { blocksToMarkdown, markdownToBlocks, type CustomEditorBlock, type CustomPartialBlock, } from "./editor/customMarkdownConverter";
package/package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { customSchema, } from "./editor/customSchema";
2
- export { stepBlock, canInsertStepOrSnippet } from "./editor/blocks/step";
2
+ export { stepBlock, canInsertStepOrSnippet, isStepsHeading } from "./editor/blocks/step";
3
3
  export { snippetBlock } from "./editor/blocks/snippet";
4
4
  export { markdownToHtml, htmlToMarkdown } from "./editor/blocks/markdown";
5
5
  export { blocksToMarkdown, markdownToBlocks, } from "./editor/customMarkdownConverter";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testomatio-editor-blocks",
3
- "version": "0.4.25",
3
+ "version": "0.4.26",
4
4
  "description": "Custom BlockNote schema, markdown conversion helpers, and UI for Testomatio-style test cases and steps.",
5
5
  "type": "module",
6
6
  "main": "./package/index.js",
@@ -47,6 +47,15 @@ const writeStepViewMode = (mode: StepViewMode) => {
47
47
  }
48
48
  };
49
49
 
50
+ /**
51
+ * Returns true when a normalised (lowercased, trailing-punctuation-stripped)
52
+ * heading text looks like a "Steps" heading.
53
+ * Accepted forms: steps, step, step(s).
54
+ */
55
+ export function isStepsHeading(text: string): boolean {
56
+ return /^step(s|\(s\))?$/.test(text);
57
+ }
58
+
50
59
  export const isEmptyParagraph = (b: any): boolean =>
51
60
  b.type === "paragraph" &&
52
61
  (!Array.isArray(b.content) ||
@@ -80,7 +89,7 @@ export function canInsertStepOrSnippet(
80
89
  .trim()
81
90
  .toLowerCase()
82
91
  .replace(/[:\-–—]$/, "");
83
- return text === "steps";
92
+ return isStepsHeading(text);
84
93
  }
85
94
  return false;
86
95
  }
@@ -162,7 +171,7 @@ export const stepBlock = createReactBlockSpec(
162
171
  .trim()
163
172
  .toLowerCase()
164
173
  .replace(/[:\-–—]$/, "");
165
- return text === "steps";
174
+ return isStepsHeading(text);
166
175
  }
167
176
  return false;
168
177
  }
@@ -863,6 +863,40 @@ describe("markdownToBlocks", () => {
863
863
  ]);
864
864
  });
865
865
 
866
+ it("parses steps under a 'Step' heading (singular)", () => {
867
+ const markdown = ["## Step", "", "* Open the app", "* Click login"].join("\n");
868
+ const blocks = markdownToBlocks(markdown);
869
+ const stepBlocks = blocks.filter((block) => block.type === "testStep");
870
+ expect(stepBlocks).toHaveLength(2);
871
+ expect(stepBlocks[0].props).toMatchObject({ stepTitle: "Open the app" });
872
+ expect(stepBlocks[1].props).toMatchObject({ stepTitle: "Click login" });
873
+ });
874
+
875
+ it("parses steps under a 'Step(s)' heading", () => {
876
+ const markdown = ["# Step(s)", "", "1. First step", "2. Second step"].join("\n");
877
+ const blocks = markdownToBlocks(markdown);
878
+ const stepBlocks = blocks.filter((block) => block.type === "testStep");
879
+ expect(stepBlocks).toHaveLength(2);
880
+ expect(stepBlocks[0].props).toMatchObject({ stepTitle: "First step", listStyle: "ordered" });
881
+ expect(stepBlocks[1].props).toMatchObject({ stepTitle: "Second step", listStyle: "ordered" });
882
+ });
883
+
884
+ it("parses steps under an h4 'step' heading (lowercase)", () => {
885
+ const markdown = ["#### step", "", "* Do something"].join("\n");
886
+ const blocks = markdownToBlocks(markdown);
887
+ const stepBlocks = blocks.filter((block) => block.type === "testStep");
888
+ expect(stepBlocks).toHaveLength(1);
889
+ expect(stepBlocks[0].props).toMatchObject({ stepTitle: "Do something" });
890
+ });
891
+
892
+ it("parses steps under a 'Step:' heading with trailing colon", () => {
893
+ const markdown = ["### Step:", "", "* Verify output"].join("\n");
894
+ const blocks = markdownToBlocks(markdown);
895
+ const stepBlocks = blocks.filter((block) => block.type === "testStep");
896
+ expect(stepBlocks).toHaveLength(1);
897
+ expect(stepBlocks[0].props).toMatchObject({ stepTitle: "Verify output" });
898
+ });
899
+
866
900
  it("handles multiple steps with expected results without extra asterisks", () => {
867
901
  const markdown = [
868
902
  "### Preconditions",
@@ -9,6 +9,7 @@ import type {
9
9
  Styles,
10
10
  } from "@blocknote/core";
11
11
  import type { customSchema } from "./customSchema";
12
+ import { isStepsHeading } from "./blocks/step";
12
13
 
13
14
  // Types derived from the custom schema so the converter stays type-safe when the schema evolves.
14
15
  type Schema = typeof customSchema;
@@ -1413,7 +1414,7 @@ export function markdownToBlocks(markdown: string): CustomPartialBlock[] {
1413
1414
  const headingText = inlineContentToPlainText(headingBlock.content as any);
1414
1415
  const normalizedHeading = headingText.trim().toLowerCase();
1415
1416
 
1416
- if (normalizedHeading.replace(/[:\-–—]$/, "") === "steps") {
1417
+ if (isStepsHeading(normalizedHeading.replace(/[:\-–—]$/, ""))) {
1417
1418
  stepsHeadingLevel = headingLevel;
1418
1419
  } else if (
1419
1420
  stepsHeadingLevel !== null &&
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ export {
4
4
  type CustomBlock,
5
5
  type CustomEditor,
6
6
  } from "./editor/customSchema";
7
- export { stepBlock, canInsertStepOrSnippet } from "./editor/blocks/step";
7
+ export { stepBlock, canInsertStepOrSnippet, isStepsHeading } from "./editor/blocks/step";
8
8
  export { snippetBlock } from "./editor/blocks/snippet";
9
9
  export { markdownToHtml, htmlToMarkdown } from "./editor/blocks/markdown";
10
10