testomatio-editor-blocks 0.4.11 → 0.4.13

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.
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createReactBlockSpec } from "@blocknote/react";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { useSnippetAutocomplete } from "../snippetAutocomplete";
5
- function SnippetDropdown({ value, placeholder, suggestions, onSelect }) {
5
+ function SnippetDropdown({ value, placeholder, suggestions, selectedId, onSelect }) {
6
6
  const [isOpen, setIsOpen] = useState(false);
7
7
  const [search, setSearch] = useState("");
8
8
  const containerRef = useRef(null);
@@ -34,11 +34,14 @@ function SnippetDropdown({ value, placeholder, suggestions, onSelect }) {
34
34
  const handleSearchChange = useCallback((event) => {
35
35
  setSearch(event.target.value);
36
36
  }, []);
37
- return (_jsxs("div", { className: "bn-snippet-dropdown", ref: containerRef, children: [_jsxs("button", { type: "button", className: "bn-snippet-dropdown__trigger", onClick: () => setIsOpen((prev) => !prev), children: [_jsx("span", { className: "bn-snippet-dropdown__text", children: value || placeholder }), _jsx("svg", { className: "bn-snippet-dropdown__chevron", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), isOpen && (_jsxs("div", { className: "bn-snippet-dropdown__panel", role: "listbox", children: [_jsxs("div", { className: "bn-snippet-dropdown__search", children: [_jsx("svg", { className: "bn-snippet-dropdown__search-icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M15.5 14H14.71L14.43 13.73C15.41 12.59 16 11.11 16 9.5C16 5.91 13.09 3 9.5 3C5.91 3 3 5.91 3 9.5C3 13.09 5.91 16 9.5 16C11.11 16 12.59 15.41 13.73 14.43L14 14.71V15.5L19 20.49L20.49 19L15.5 14ZM9.5 14C7.01 14 5 11.99 5 9.5C5 7.01 7.01 5 9.5 5C11.99 5 14 7.01 14 9.5C14 11.99 11.99 14 9.5 14Z", fill: "currentColor" }) }), _jsx("input", { ref: searchRef, type: "text", className: "bn-snippet-dropdown__search-input", placeholder: "Search", value: search, onChange: handleSearchChange })] }), _jsxs("div", { className: "bn-snippet-dropdown__list", children: [filtered.map((suggestion) => (_jsx("button", { type: "button", role: "option", className: "bn-snippet-dropdown__item", onMouseDown: (event) => {
38
- event.preventDefault();
39
- onSelect(suggestion);
40
- setIsOpen(false);
41
- }, tabIndex: -1, children: suggestion.title }, suggestion.id))), filtered.length === 0 && (_jsx("div", { className: "bn-snippet-dropdown__empty", children: "No snippets found" }))] })] }))] }));
37
+ return (_jsxs("div", { className: "bn-snippet-dropdown", ref: containerRef, children: [_jsxs("button", { type: "button", className: "bn-snippet-dropdown__trigger", onClick: () => setIsOpen((prev) => !prev), children: [_jsx("span", { className: "bn-snippet-dropdown__text", children: value || placeholder }), _jsx("svg", { className: "bn-snippet-dropdown__chevron", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), isOpen && (_jsxs("div", { className: "bn-snippet-dropdown__panel", role: "listbox", children: [_jsx("div", { className: "bn-snippet-dropdown__search-wrapper", children: _jsxs("div", { className: "bn-snippet-dropdown__search", children: [_jsx("svg", { className: "bn-snippet-dropdown__search-icon", width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M12.917 11.667h-.659l-.233-.225a5.417 5.417 0 0 0 1.308-3.525 5.417 5.417 0 1 0-5.416 5.416 5.417 5.417 0 0 0 3.525-1.308l.225.233v.659l4.166 4.158 1.242-1.242-4.158-4.166Zm-5 0a3.745 3.745 0 0 1-3.75-3.75 3.745 3.745 0 0 1 3.75-3.75 3.745 3.745 0 0 1 3.75 3.75 3.745 3.745 0 0 1-3.75 3.75Z", fill: "currentColor" }) }), _jsx("input", { ref: searchRef, type: "text", className: "bn-snippet-dropdown__search-input", placeholder: "Search", value: search, onChange: handleSearchChange })] }) }), _jsxs("div", { className: "bn-snippet-dropdown__list", children: [filtered.map((suggestion) => {
38
+ const isSelected = suggestion.id === selectedId;
39
+ return (_jsxs("button", { type: "button", role: "option", "aria-selected": isSelected, className: `bn-snippet-dropdown__item${isSelected ? " bn-snippet-dropdown__item--selected" : ""}`, onMouseDown: (event) => {
40
+ event.preventDefault();
41
+ onSelect(suggestion);
42
+ setIsOpen(false);
43
+ }, tabIndex: -1, children: [_jsx("span", { className: "bn-snippet-dropdown__item-title", children: suggestion.title }), isSelected && (_jsx("svg", { className: "bn-snippet-dropdown__item-check", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17Z", fill: "currentColor" }) }))] }, suggestion.id));
44
+ }), filtered.length === 0 && (_jsx("div", { className: "bn-snippet-dropdown__empty", children: "No snippets found" }))] })] }))] }));
42
45
  }
43
46
  export const snippetBlock = createReactBlockSpec({
44
47
  type: "snippet",
@@ -99,6 +102,6 @@ export const snippetBlock = createReactBlockSpec({
99
102
  if (!hasSnippets) {
100
103
  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." }) }));
101
104
  }
102
- 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, onSelect: handleSnippetSelect })] }), isSnippetSelected && (_jsx("div", { className: "bn-snippet__content", children: snippetData }))] }));
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 } }))] }));
103
106
  },
104
107
  });
@@ -65,7 +65,7 @@ function normalizeSnippetSuggestions(snippets) {
65
65
  return parseSnippetsFromJsonApi(snippets);
66
66
  }
67
67
  function normalizeJsonApiResource(resource) {
68
- var _a, _b, _c;
68
+ var _a, _b, _c, _d;
69
69
  if (!resource)
70
70
  return null;
71
71
  const attrs = resource.attributes;
@@ -76,8 +76,8 @@ function normalizeJsonApiResource(resource) {
76
76
  return {
77
77
  id: String(id),
78
78
  title: String(title),
79
- body: (_b = attrs === null || attrs === void 0 ? void 0 : attrs.body) !== null && _b !== void 0 ? _b : null,
80
- description: (_c = attrs === null || attrs === void 0 ? void 0 : attrs.description) !== null && _c !== void 0 ? _c : null,
79
+ body: (_c = (_b = attrs === null || attrs === void 0 ? void 0 : attrs.body) !== null && _b !== void 0 ? _b : attrs === null || attrs === void 0 ? void 0 : attrs.description) !== null && _c !== void 0 ? _c : null,
80
+ description: (_d = attrs === null || attrs === void 0 ? void 0 : attrs.description) !== null && _d !== void 0 ? _d : null,
81
81
  usageCount: coerceNumber(attrs === null || attrs === void 0 ? void 0 : attrs["usage-count"]),
82
82
  isSnippet: true,
83
83
  };
@@ -224,6 +224,10 @@ html.dark .bn-snippet-dropdown__panel {
224
224
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
225
225
  }
226
226
 
227
+ html.dark .bn-snippet-dropdown__search-wrapper {
228
+ border-bottom-color: #404040;
229
+ }
230
+
227
231
  html.dark .bn-snippet-dropdown__search {
228
232
  border-color: #404040;
229
233
  }
@@ -240,8 +244,12 @@ html.dark .bn-snippet-dropdown__search-input::placeholder {
240
244
  color: #525252;
241
245
  }
242
246
 
243
- html.dark .bn-snippet-dropdown__list {
244
- border-top-color: #404040;
247
+ html.dark .bn-snippet-dropdown__item--selected {
248
+ background: #333333;
249
+ }
250
+
251
+ html.dark .bn-snippet-dropdown__item-check {
252
+ color: #fafafa;
245
253
  }
246
254
 
247
255
  html.dark .bn-snippet-dropdown__chevron {
@@ -609,7 +617,7 @@ html.dark .bn-step-image-preview__content {
609
617
  position: absolute;
610
618
  left: 0;
611
619
  top: calc(100% + 4px);
612
- width: 260px;
620
+ width: 280px;
613
621
  background: white;
614
622
  border: 1px solid #e5e5e5;
615
623
  border-radius: 8px;
@@ -620,13 +628,17 @@ html.dark .bn-step-image-preview__content {
620
628
  padding: 8px 0;
621
629
  }
622
630
 
631
+ .bn-snippet-dropdown__search-wrapper {
632
+ padding: 4px 16px 12px;
633
+ border-bottom: 1px solid #e5e5e5;
634
+ }
635
+
623
636
  .bn-snippet-dropdown__search {
624
637
  display: flex;
625
638
  align-items: center;
626
639
  gap: 8px;
627
640
  height: 32px;
628
641
  padding: 0 12px;
629
- margin: 0 16px 12px;
630
642
  border: 1px solid #d4d4d4;
631
643
  border-radius: 6px;
632
644
  transition: border-color 120ms ease;
@@ -638,8 +650,8 @@ html.dark .bn-step-image-preview__content {
638
650
 
639
651
  .bn-snippet-dropdown__search-icon {
640
652
  flex-shrink: 0;
641
- width: 24px;
642
- height: 24px;
653
+ width: 20px;
654
+ height: 20px;
643
655
  color: #a4a4a4;
644
656
  }
645
657
 
@@ -663,7 +675,6 @@ html.dark .bn-step-image-preview__content {
663
675
  .bn-snippet-dropdown__list {
664
676
  max-height: 252px;
665
677
  overflow-y: auto;
666
- border-top: 1px solid #e5e5e5;
667
678
  }
668
679
 
669
680
  .bn-snippet-dropdown__item {
@@ -682,9 +693,25 @@ html.dark .bn-step-image-preview__content {
682
693
  color: var(--text-primary);
683
694
  text-align: left;
684
695
  cursor: pointer;
685
- white-space: nowrap;
696
+ }
697
+
698
+ .bn-snippet-dropdown__item-title {
699
+ flex: 1;
700
+ min-width: 0;
686
701
  overflow: hidden;
687
702
  text-overflow: ellipsis;
703
+ white-space: nowrap;
704
+ }
705
+
706
+ .bn-snippet-dropdown__item-check {
707
+ flex-shrink: 0;
708
+ width: 16px;
709
+ height: 16px;
710
+ color: var(--text-primary);
711
+ }
712
+
713
+ .bn-snippet-dropdown__item--selected {
714
+ background: #fafafa;
688
715
  }
689
716
 
690
717
  .bn-snippet-dropdown__item:hover {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testomatio-editor-blocks",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
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",
@@ -7,10 +7,11 @@ type SnippetDropdownProps = {
7
7
  value: string;
8
8
  placeholder: string;
9
9
  suggestions: SnippetSuggestion[];
10
+ selectedId: string;
10
11
  onSelect: (suggestion: SnippetSuggestion) => void;
11
12
  };
12
13
 
13
- function SnippetDropdown({ value, placeholder, suggestions, onSelect }: SnippetDropdownProps) {
14
+ function SnippetDropdown({ value, placeholder, suggestions, selectedId, onSelect }: SnippetDropdownProps) {
14
15
  const [isOpen, setIsOpen] = useState(false);
15
16
  const [search, setSearch] = useState("");
16
17
  const containerRef = useRef<HTMLDivElement>(null);
@@ -61,36 +62,47 @@ function SnippetDropdown({ value, placeholder, suggestions, onSelect }: SnippetD
61
62
  </button>
62
63
  {isOpen && (
63
64
  <div className="bn-snippet-dropdown__panel" role="listbox">
64
- <div className="bn-snippet-dropdown__search">
65
- <svg className="bn-snippet-dropdown__search-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
66
- <path d="M15.5 14H14.71L14.43 13.73C15.41 12.59 16 11.11 16 9.5C16 5.91 13.09 3 9.5 3C5.91 3 3 5.91 3 9.5C3 13.09 5.91 16 9.5 16C11.11 16 12.59 15.41 13.73 14.43L14 14.71V15.5L19 20.49L20.49 19L15.5 14ZM9.5 14C7.01 14 5 11.99 5 9.5C5 7.01 7.01 5 9.5 5C11.99 5 14 7.01 14 9.5C14 11.99 11.99 14 9.5 14Z" fill="currentColor"/>
67
- </svg>
68
- <input
69
- ref={searchRef}
70
- type="text"
71
- className="bn-snippet-dropdown__search-input"
72
- placeholder="Search"
73
- value={search}
74
- onChange={handleSearchChange}
75
- />
65
+ <div className="bn-snippet-dropdown__search-wrapper">
66
+ <div className="bn-snippet-dropdown__search">
67
+ <svg className="bn-snippet-dropdown__search-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
68
+ <path d="M12.917 11.667h-.659l-.233-.225a5.417 5.417 0 0 0 1.308-3.525 5.417 5.417 0 1 0-5.416 5.416 5.417 5.417 0 0 0 3.525-1.308l.225.233v.659l4.166 4.158 1.242-1.242-4.158-4.166Zm-5 0a3.745 3.745 0 0 1-3.75-3.75 3.745 3.745 0 0 1 3.75-3.75 3.745 3.745 0 0 1 3.75 3.75 3.745 3.745 0 0 1-3.75 3.75Z" fill="currentColor"/>
69
+ </svg>
70
+ <input
71
+ ref={searchRef}
72
+ type="text"
73
+ className="bn-snippet-dropdown__search-input"
74
+ placeholder="Search"
75
+ value={search}
76
+ onChange={handleSearchChange}
77
+ />
78
+ </div>
76
79
  </div>
77
80
  <div className="bn-snippet-dropdown__list">
78
- {filtered.map((suggestion) => (
79
- <button
80
- type="button"
81
- key={suggestion.id}
82
- role="option"
83
- className="bn-snippet-dropdown__item"
84
- onMouseDown={(event) => {
85
- event.preventDefault();
86
- onSelect(suggestion);
87
- setIsOpen(false);
88
- }}
89
- tabIndex={-1}
90
- >
91
- {suggestion.title}
92
- </button>
93
- ))}
81
+ {filtered.map((suggestion) => {
82
+ const isSelected = suggestion.id === selectedId;
83
+ return (
84
+ <button
85
+ type="button"
86
+ key={suggestion.id}
87
+ role="option"
88
+ aria-selected={isSelected}
89
+ className={`bn-snippet-dropdown__item${isSelected ? " bn-snippet-dropdown__item--selected" : ""}`}
90
+ onMouseDown={(event) => {
91
+ event.preventDefault();
92
+ onSelect(suggestion);
93
+ setIsOpen(false);
94
+ }}
95
+ tabIndex={-1}
96
+ >
97
+ <span className="bn-snippet-dropdown__item-title">{suggestion.title}</span>
98
+ {isSelected && (
99
+ <svg className="bn-snippet-dropdown__item-check" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
100
+ <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17Z" fill="currentColor"/>
101
+ </svg>
102
+ )}
103
+ </button>
104
+ );
105
+ })}
94
106
  {filtered.length === 0 && (
95
107
  <div className="bn-snippet-dropdown__empty">No snippets found</div>
96
108
  )}
@@ -178,11 +190,12 @@ export const snippetBlock = createReactBlockSpec(
178
190
  value={snippetTitle}
179
191
  placeholder="Select Snippet"
180
192
  suggestions={snippetSuggestions}
193
+ selectedId={snippetId}
181
194
  onSelect={handleSnippetSelect}
182
195
  />
183
196
  </div>
184
- {isSnippetSelected && (
185
- <div className="bn-snippet__content">{snippetData}</div>
197
+ {isSnippetSelected && snippetData && (
198
+ <div className="bn-snippet__content" dangerouslySetInnerHTML={{ __html: snippetData }} />
186
199
  )}
187
200
  </div>
188
201
  );
@@ -115,7 +115,7 @@ function normalizeJsonApiResource(resource: SnippetJsonApiResource | null | unde
115
115
  return {
116
116
  id: String(id),
117
117
  title: String(title),
118
- body: attrs?.body ?? null,
118
+ body: attrs?.body ?? attrs?.description ?? null,
119
119
  description: attrs?.description ?? null,
120
120
  usageCount: coerceNumber(attrs?.["usage-count"]),
121
121
  isSnippet: true,
@@ -224,6 +224,10 @@ html.dark .bn-snippet-dropdown__panel {
224
224
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
225
225
  }
226
226
 
227
+ html.dark .bn-snippet-dropdown__search-wrapper {
228
+ border-bottom-color: #404040;
229
+ }
230
+
227
231
  html.dark .bn-snippet-dropdown__search {
228
232
  border-color: #404040;
229
233
  }
@@ -240,8 +244,12 @@ html.dark .bn-snippet-dropdown__search-input::placeholder {
240
244
  color: #525252;
241
245
  }
242
246
 
243
- html.dark .bn-snippet-dropdown__list {
244
- border-top-color: #404040;
247
+ html.dark .bn-snippet-dropdown__item--selected {
248
+ background: #333333;
249
+ }
250
+
251
+ html.dark .bn-snippet-dropdown__item-check {
252
+ color: #fafafa;
245
253
  }
246
254
 
247
255
  html.dark .bn-snippet-dropdown__chevron {
@@ -609,7 +617,7 @@ html.dark .bn-step-image-preview__content {
609
617
  position: absolute;
610
618
  left: 0;
611
619
  top: calc(100% + 4px);
612
- width: 260px;
620
+ width: 280px;
613
621
  background: white;
614
622
  border: 1px solid #e5e5e5;
615
623
  border-radius: 8px;
@@ -620,13 +628,17 @@ html.dark .bn-step-image-preview__content {
620
628
  padding: 8px 0;
621
629
  }
622
630
 
631
+ .bn-snippet-dropdown__search-wrapper {
632
+ padding: 4px 16px 12px;
633
+ border-bottom: 1px solid #e5e5e5;
634
+ }
635
+
623
636
  .bn-snippet-dropdown__search {
624
637
  display: flex;
625
638
  align-items: center;
626
639
  gap: 8px;
627
640
  height: 32px;
628
641
  padding: 0 12px;
629
- margin: 0 16px 12px;
630
642
  border: 1px solid #d4d4d4;
631
643
  border-radius: 6px;
632
644
  transition: border-color 120ms ease;
@@ -638,8 +650,8 @@ html.dark .bn-step-image-preview__content {
638
650
 
639
651
  .bn-snippet-dropdown__search-icon {
640
652
  flex-shrink: 0;
641
- width: 24px;
642
- height: 24px;
653
+ width: 20px;
654
+ height: 20px;
643
655
  color: #a4a4a4;
644
656
  }
645
657
 
@@ -663,7 +675,6 @@ html.dark .bn-step-image-preview__content {
663
675
  .bn-snippet-dropdown__list {
664
676
  max-height: 252px;
665
677
  overflow-y: auto;
666
- border-top: 1px solid #e5e5e5;
667
678
  }
668
679
 
669
680
  .bn-snippet-dropdown__item {
@@ -682,9 +693,25 @@ html.dark .bn-step-image-preview__content {
682
693
  color: var(--text-primary);
683
694
  text-align: left;
684
695
  cursor: pointer;
685
- white-space: nowrap;
696
+ }
697
+
698
+ .bn-snippet-dropdown__item-title {
699
+ flex: 1;
700
+ min-width: 0;
686
701
  overflow: hidden;
687
702
  text-overflow: ellipsis;
703
+ white-space: nowrap;
704
+ }
705
+
706
+ .bn-snippet-dropdown__item-check {
707
+ flex-shrink: 0;
708
+ width: 16px;
709
+ height: 16px;
710
+ color: var(--text-primary);
711
+ }
712
+
713
+ .bn-snippet-dropdown__item--selected {
714
+ background: #fafafa;
688
715
  }
689
716
 
690
717
  .bn-snippet-dropdown__item:hover {