testomatio-editor-blocks 0.4.14 → 0.4.16

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.
@@ -68,6 +68,14 @@ export const snippetBlock = createReactBlockSpec({
68
68
  const snippetSuggestions = useSnippetAutocomplete();
69
69
  const hasSnippets = snippetSuggestions.length > 0;
70
70
  const isSnippetSelected = snippetId.length > 0;
71
+ const resolvedTitle = useMemo(() => {
72
+ var _a, _b;
73
+ if (snippetTitle)
74
+ return snippetTitle;
75
+ if (!snippetId || snippetSuggestions.length === 0)
76
+ return "";
77
+ return (_b = (_a = snippetSuggestions.find((s) => s.id === snippetId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : "";
78
+ }, [snippetTitle, snippetId, snippetSuggestions]);
71
79
  const handleSnippetSelect = useCallback((suggestion) => {
72
80
  var _a;
73
81
  const rawBody = (_a = suggestion.body) !== null && _a !== void 0 ? _a : "";
@@ -102,6 +110,11 @@ export const snippetBlock = createReactBlockSpec({
102
110
  if (!hasSnippets) {
103
111
  return (_jsx("div", { className: "bn-teststep bn-snippet", "data-block-id": block.id, children: _jsx("p", { className: "bn-snippet__empty", children: "No snippets in this project." }) }));
104
112
  }
105
- return (_jsxs("div", { className: "bn-teststep bn-snippet", "data-block-id": block.id, onFocus: handleFieldFocus, children: [_jsxs("div", { className: "bn-snippet__header", children: [_jsx("span", { className: "bn-snippet__label", children: "Snippet" }), _jsx(SnippetDropdown, { value: snippetTitle, placeholder: "Select Snippet", suggestions: snippetSuggestions, selectedId: snippetId, onSelect: handleSnippetSelect })] }), isSnippetSelected && snippetData && (_jsx("div", { className: "bn-snippet__content", dangerouslySetInnerHTML: { __html: snippetData } }))] }));
113
+ return (_jsxs("div", { className: "bn-teststep bn-snippet", "data-block-id": block.id, onFocus: handleFieldFocus, children: [_jsxs("div", { className: "bn-snippet__header", children: [_jsx("span", { className: "bn-snippet__label", children: "Snippet" }), _jsx(SnippetDropdown, { value: resolvedTitle, placeholder: "Select Snippet", suggestions: snippetSuggestions, selectedId: snippetId, onSelect: handleSnippetSelect })] }), isSnippetSelected && snippetData && (_jsx("div", { className: "bn-snippet__content", dangerouslySetInnerHTML: {
114
+ __html: snippetData
115
+ .replace(/&/g, "&")
116
+ .replace(/</g, "&lt;")
117
+ .replace(/>/g, "&gt;"),
118
+ } }))] }));
106
119
  },
107
120
  });
@@ -1028,7 +1028,7 @@ function parseParagraph(lines, index) {
1028
1028
  }
1029
1029
  function parseSnippetWrapper(lines, index) {
1030
1030
  const trimmed = lines[index].trim();
1031
- const startMatch = trimmed.match(/^<!--\s*begin snippet\s*#?([^\s>]+)\s*-->/i);
1031
+ const startMatch = trimmed.match(/^<!--\s*begin snippet\s*#?\s*([^\s>]+)\s*-->/i);
1032
1032
  if (!startMatch) {
1033
1033
  return null;
1034
1034
  }
@@ -1037,7 +1037,7 @@ function parseSnippetWrapper(lines, index) {
1037
1037
  let next = index + 1;
1038
1038
  while (next < lines.length) {
1039
1039
  const maybeEnd = lines[next].trim();
1040
- const endMatch = maybeEnd.match(/^<!--\s*end snippet\s*#?([^\s>]+)?\s*-->/i);
1040
+ const endMatch = maybeEnd.match(/^<!--\s*end snippet\s*#?\s*([^\s>]+)?\s*-->/i);
1041
1041
  if (endMatch) {
1042
1042
  const endId = endMatch[1];
1043
1043
  if (!endId || endId === snippetId) {
@@ -1048,7 +1048,7 @@ function parseSnippetWrapper(lines, index) {
1048
1048
  next += 1;
1049
1049
  continue;
1050
1050
  }
1051
- const otherStart = maybeEnd.match(/^<!--\s*begin snippet\s*#?([^\s>]+)\s*-->/i);
1051
+ const otherStart = maybeEnd.match(/^<!--\s*begin snippet\s*#?\s*([^\s>]+)\s*-->/i);
1052
1052
  if (otherStart) {
1053
1053
  // Skip nested snippet wrappers from the body entirely.
1054
1054
  next += 1;
@@ -498,11 +498,11 @@ html.dark .bn-step-image-preview__content {
498
498
  }
499
499
 
500
500
  .bn-teststep__view-toggle--horizontal[data-tooltip]::after {
501
- right: auto;
502
- top: auto;
503
- bottom: calc(100% + 6px);
504
- left: 50%;
505
- transform: translateX(-50%);
501
+ bottom: auto;
502
+ left: auto;
503
+ right: calc(100% + 6px);
504
+ top: 50%;
505
+ transform: translateY(-50%) rotate(-90deg);
506
506
  }
507
507
 
508
508
  .bn-teststep__horizontal-fields {
@@ -656,9 +656,9 @@ html.dark .bn-step-image-preview__content {
656
656
  }
657
657
 
658
658
  .bn-snippet-dropdown__search-input {
659
- border: none;
660
- outline: none;
661
- background: transparent;
659
+ border: none !important;
660
+ outline: none !important;
661
+ background: transparent !important;
662
662
  font-family: inherit;
663
663
  font-size: 14px !important;
664
664
  font-weight: 500;
@@ -667,7 +667,11 @@ html.dark .bn-step-image-preview__content {
667
667
  width: 100%;
668
668
  height: auto;
669
669
  display: inline !important;
670
- padding: 0;
670
+ padding: 0 !important;
671
+ appearance: none !important;
672
+ -webkit-appearance: none !important;
673
+ border-radius: 0 !important;
674
+ box-shadow: none !important;
671
675
  }
672
676
 
673
677
  .bn-snippet-dropdown__search-input::placeholder {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testomatio-editor-blocks",
3
- "version": "0.4.14",
3
+ "version": "0.4.16",
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",
@@ -141,6 +141,12 @@ export const snippetBlock = createReactBlockSpec(
141
141
  const hasSnippets = snippetSuggestions.length > 0;
142
142
  const isSnippetSelected = snippetId.length > 0;
143
143
 
144
+ const resolvedTitle = useMemo(() => {
145
+ if (snippetTitle) return snippetTitle;
146
+ if (!snippetId || snippetSuggestions.length === 0) return "";
147
+ return snippetSuggestions.find((s) => s.id === snippetId)?.title ?? "";
148
+ }, [snippetTitle, snippetId, snippetSuggestions]);
149
+
144
150
  const handleSnippetSelect = useCallback(
145
151
  (suggestion: SnippetSuggestion) => {
146
152
  const rawBody = suggestion.body ?? "";
@@ -187,7 +193,7 @@ export const snippetBlock = createReactBlockSpec(
187
193
  <div className="bn-snippet__header">
188
194
  <span className="bn-snippet__label">Snippet</span>
189
195
  <SnippetDropdown
190
- value={snippetTitle}
196
+ value={resolvedTitle}
191
197
  placeholder="Select Snippet"
192
198
  suggestions={snippetSuggestions}
193
199
  selectedId={snippetId}
@@ -195,7 +201,15 @@ export const snippetBlock = createReactBlockSpec(
195
201
  />
196
202
  </div>
197
203
  {isSnippetSelected && snippetData && (
198
- <div className="bn-snippet__content" dangerouslySetInnerHTML={{ __html: snippetData }} />
204
+ <div
205
+ className="bn-snippet__content"
206
+ dangerouslySetInnerHTML={{
207
+ __html: snippetData
208
+ .replace(/&/g, "&amp;")
209
+ .replace(/</g, "&lt;")
210
+ .replace(/>/g, "&gt;"),
211
+ }}
212
+ />
199
213
  )}
200
214
  </div>
201
215
  );
@@ -385,6 +385,28 @@ describe("markdownToBlocks", () => {
385
385
  ]);
386
386
  });
387
387
 
388
+ it("parses snippet markdown with space between # and ID", () => {
389
+ const markdown = [
390
+ "<!-- begin snippet # 22289 -->",
391
+ "* Fill `<Email>` with correct registered email",
392
+ "* Verify that the update to the target is successful",
393
+ "<!-- end snippet # 22289 -->",
394
+ ].join("\n");
395
+
396
+ expect(markdownToBlocks(markdown)).toEqual([
397
+ {
398
+ type: "snippet",
399
+ props: {
400
+ snippetId: "22289",
401
+ snippetTitle: "",
402
+ snippetData: "* Fill `<Email>` with correct registered email\n* Verify that the update to the target is successful",
403
+ snippetExpectedResult: "",
404
+ },
405
+ children: [],
406
+ },
407
+ ]);
408
+ });
409
+
388
410
  it("parses snippet bodies and ignores nested snippet markers", () => {
389
411
  const markdown = [
390
412
  "<!-- begin snippet #888 -->",
@@ -1238,7 +1238,7 @@ function parseSnippetWrapper(
1238
1238
  index: number,
1239
1239
  ): { block: CustomPartialBlock; nextIndex: number } | null {
1240
1240
  const trimmed = lines[index].trim();
1241
- const startMatch = trimmed.match(/^<!--\s*begin snippet\s*#?([^\s>]+)\s*-->/i);
1241
+ const startMatch = trimmed.match(/^<!--\s*begin snippet\s*#?\s*([^\s>]+)\s*-->/i);
1242
1242
  if (!startMatch) {
1243
1243
  return null;
1244
1244
  }
@@ -1249,7 +1249,7 @@ function parseSnippetWrapper(
1249
1249
 
1250
1250
  while (next < lines.length) {
1251
1251
  const maybeEnd = lines[next].trim();
1252
- const endMatch = maybeEnd.match(/^<!--\s*end snippet\s*#?([^\s>]+)?\s*-->/i);
1252
+ const endMatch = maybeEnd.match(/^<!--\s*end snippet\s*#?\s*([^\s>]+)?\s*-->/i);
1253
1253
  if (endMatch) {
1254
1254
  const endId = endMatch[1];
1255
1255
  if (!endId || endId === snippetId) {
@@ -1260,7 +1260,7 @@ function parseSnippetWrapper(
1260
1260
  next += 1;
1261
1261
  continue;
1262
1262
  }
1263
- const otherStart = maybeEnd.match(/^<!--\s*begin snippet\s*#?([^\s>]+)\s*-->/i);
1263
+ const otherStart = maybeEnd.match(/^<!--\s*begin snippet\s*#?\s*([^\s>]+)\s*-->/i);
1264
1264
  if (otherStart) {
1265
1265
  // Skip nested snippet wrappers from the body entirely.
1266
1266
  next += 1;
@@ -498,11 +498,11 @@ html.dark .bn-step-image-preview__content {
498
498
  }
499
499
 
500
500
  .bn-teststep__view-toggle--horizontal[data-tooltip]::after {
501
- right: auto;
502
- top: auto;
503
- bottom: calc(100% + 6px);
504
- left: 50%;
505
- transform: translateX(-50%);
501
+ bottom: auto;
502
+ left: auto;
503
+ right: calc(100% + 6px);
504
+ top: 50%;
505
+ transform: translateY(-50%) rotate(-90deg);
506
506
  }
507
507
 
508
508
  .bn-teststep__horizontal-fields {
@@ -656,9 +656,9 @@ html.dark .bn-step-image-preview__content {
656
656
  }
657
657
 
658
658
  .bn-snippet-dropdown__search-input {
659
- border: none;
660
- outline: none;
661
- background: transparent;
659
+ border: none !important;
660
+ outline: none !important;
661
+ background: transparent !important;
662
662
  font-family: inherit;
663
663
  font-size: 14px !important;
664
664
  font-weight: 500;
@@ -667,7 +667,11 @@ html.dark .bn-step-image-preview__content {
667
667
  width: 100%;
668
668
  height: auto;
669
669
  display: inline !important;
670
- padding: 0;
670
+ padding: 0 !important;
671
+ appearance: none !important;
672
+ -webkit-appearance: none !important;
673
+ border-radius: 0 !important;
674
+ box-shadow: none !important;
671
675
  }
672
676
 
673
677
  .bn-snippet-dropdown__search-input::placeholder {