testomatio-editor-blocks 0.4.70 → 0.4.71

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.
@@ -106,6 +106,19 @@ export const testMetaBlock = createReactBlockSpec({
106
106
  const editableFields = fields
107
107
  .map((field, index) => ({ field, index }))
108
108
  .filter(({ field }) => !ID_KEYS.has(field.key.trim().toLowerCase()));
109
- return (_jsxs("div", { className: "bn-testmeta", "data-block-id": block.id, "data-kind": kind, contentEditable: false, suppressContentEditableWarning: true, draggable: false, children: [_jsxs("div", { className: "bn-testmeta__header", children: [_jsx("span", { className: "bn-testmeta__label", children: kind.toUpperCase() }), (idField === null || idField === void 0 ? void 0 : idField.value) && _jsx("span", { className: "bn-testmeta__id", children: idField.value }), _jsx(AddFieldMenu, { kind: kind, usedKeys: usedKeys, onPick: handleAddField })] }), editableFields.length > 0 && (_jsx("div", { className: "bn-testmeta__rows", children: editableFields.map(({ field, index }) => (_jsxs("div", { className: "bn-testmeta__row", children: [_jsx("input", { className: "bn-testmeta__key bn-testmeta__key--input", type: "text", value: field.key, placeholder: "key", spellCheck: false, onChange: (e) => handleKeyChange(index, e.target.value) }), _jsx("input", { className: "bn-testmeta__value", type: "text", value: field.value, placeholder: "value", spellCheck: false, onChange: (e) => handleValueChange(index, e.target.value) }), _jsx("button", { type: "button", className: "bn-testmeta__remove", "aria-label": "Remove field", title: "Remove field", onClick: () => handleRemove(index), children: "\u00D7" })] }, index))) }))] }));
109
+ // Compact (reading) view: collapse the rows into a single truncated line
110
+ // built only from fields that actually have a value — keys without values
111
+ // are an editing-only concern and never appear in the compact summary (the
112
+ // expanded rows still show them so they can be filled in). The
113
+ // expand/collapse toggle pinned to the far right reveals the full rows.
114
+ const summaryText = editableFields
115
+ .filter(({ field }) => field.key.trim().length > 0 && field.value.trim().length > 0)
116
+ .map(({ field }) => `${field.key}: ${field.value}`)
117
+ .join(" · ");
118
+ // Nothing readable to summarise (no fields, or only empty values) -> start
119
+ // expanded so the block is immediately editable. `expanded` is UI-only
120
+ // state — never serialized.
121
+ const [expanded, setExpanded] = useState(() => summaryText.length === 0);
122
+ return (_jsxs("div", { className: `bn-testmeta${expanded ? " bn-testmeta--expanded" : " bn-testmeta--collapsed"}`, "data-block-id": block.id, "data-kind": kind, contentEditable: false, suppressContentEditableWarning: true, draggable: false, children: [_jsxs("div", { className: "bn-testmeta__header", children: [_jsx("span", { className: "bn-testmeta__label", children: kind.toUpperCase() }), (idField === null || idField === void 0 ? void 0 : idField.value) && _jsx("span", { className: "bn-testmeta__id", children: idField.value }), !expanded && (_jsx("button", { type: "button", className: "bn-testmeta__summary", title: summaryText || "No metadata yet", onClick: () => setExpanded(true), children: summaryText || _jsx("span", { className: "bn-testmeta__summary--empty", children: "No metadata" }) })), _jsxs("div", { className: "bn-testmeta__actions", children: [expanded && _jsx(AddFieldMenu, { kind: kind, usedKeys: usedKeys, onPick: handleAddField }), _jsx("button", { type: "button", className: `bn-testmeta__toggle${expanded ? " bn-testmeta__toggle--expanded" : ""}`, "aria-expanded": expanded, "aria-label": expanded ? "Collapse metadata" : "Expand metadata", title: expanded ? "Collapse" : "Expand", onClick: () => setExpanded((prev) => !prev), children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), expanded && editableFields.length > 0 && (_jsx("div", { className: "bn-testmeta__rows", children: editableFields.map(({ field, index }) => (_jsxs("div", { className: "bn-testmeta__row", children: [_jsx("input", { className: "bn-testmeta__key bn-testmeta__key--input", type: "text", value: field.key, placeholder: "key", spellCheck: false, onChange: (e) => handleKeyChange(index, e.target.value) }), _jsx("input", { className: "bn-testmeta__value", type: "text", value: field.value, placeholder: "value", spellCheck: false, onChange: (e) => handleValueChange(index, e.target.value) }), _jsx("button", { type: "button", className: "bn-testmeta__remove", "aria-label": "Remove field", title: "Remove field", onClick: () => handleRemove(index), children: "\u00D7" })] }, index))) }))] }));
110
123
  },
111
124
  });
@@ -752,8 +752,69 @@ html.dark .bn-teststep__view-toggle--compact svg {
752
752
  margin-left: 8px;
753
753
  }
754
754
 
755
- .bn-testmeta__header .bn-testmeta__add-wrap {
755
+ /* Add button + expand/collapse toggle live in a right-pinned action group. */
756
+ .bn-testmeta__header .bn-testmeta__actions {
756
757
  margin-left: auto;
758
+ display: inline-flex;
759
+ align-items: center;
760
+ gap: 2px;
761
+ flex-shrink: 0;
762
+ }
763
+
764
+ /* Compact one-liner: the metadata rendered as truncated read text, click to
765
+ expand. Takes the remaining header width and ellipsizes when it overflows. */
766
+ .bn-testmeta__summary {
767
+ flex: 1 1 auto;
768
+ min-width: 0;
769
+ overflow: hidden;
770
+ white-space: nowrap;
771
+ text-overflow: ellipsis;
772
+ text-align: left;
773
+ font-family: inherit;
774
+ font-size: 13px;
775
+ color: var(--text-muted);
776
+ background: transparent;
777
+ border: none;
778
+ padding: 0;
779
+ cursor: pointer;
780
+ }
781
+
782
+ .bn-testmeta__summary:hover {
783
+ color: var(--text-primary);
784
+ }
785
+
786
+ .bn-testmeta__summary--empty {
787
+ font-style: italic;
788
+ opacity: 0.7;
789
+ }
790
+
791
+ .bn-testmeta__toggle {
792
+ width: 24px;
793
+ height: 24px;
794
+ display: inline-flex;
795
+ align-items: center;
796
+ justify-content: center;
797
+ color: var(--text-muted);
798
+ background: transparent;
799
+ border: none;
800
+ border-radius: 6px;
801
+ cursor: pointer;
802
+ padding: 0;
803
+ flex-shrink: 0;
804
+ transition: background-color 120ms ease;
805
+ }
806
+
807
+ .bn-testmeta__toggle:hover {
808
+ background: var(--step-bg-button-hover);
809
+ color: var(--text-primary);
810
+ }
811
+
812
+ .bn-testmeta__toggle svg {
813
+ transition: transform 150ms ease;
814
+ }
815
+
816
+ .bn-testmeta__toggle--expanded svg {
817
+ transform: rotate(180deg);
757
818
  }
758
819
 
759
820
  .bn-testmeta__label {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testomatio-editor-blocks",
3
- "version": "0.4.70",
3
+ "version": "0.4.71",
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",
@@ -187,9 +187,23 @@ export const testMetaBlock = createReactBlockSpec(
187
187
  .map((field, index) => ({ field, index }))
188
188
  .filter(({ field }) => !ID_KEYS.has(field.key.trim().toLowerCase()));
189
189
 
190
+ // Compact (reading) view: collapse the rows into a single truncated line
191
+ // built only from fields that actually have a value — keys without values
192
+ // are an editing-only concern and never appear in the compact summary (the
193
+ // expanded rows still show them so they can be filled in). The
194
+ // expand/collapse toggle pinned to the far right reveals the full rows.
195
+ const summaryText = editableFields
196
+ .filter(({ field }) => field.key.trim().length > 0 && field.value.trim().length > 0)
197
+ .map(({ field }) => `${field.key}: ${field.value}`)
198
+ .join(" · ");
199
+ // Nothing readable to summarise (no fields, or only empty values) -> start
200
+ // expanded so the block is immediately editable. `expanded` is UI-only
201
+ // state — never serialized.
202
+ const [expanded, setExpanded] = useState(() => summaryText.length === 0);
203
+
190
204
  return (
191
205
  <div
192
- className="bn-testmeta"
206
+ className={`bn-testmeta${expanded ? " bn-testmeta--expanded" : " bn-testmeta--collapsed"}`}
193
207
  data-block-id={block.id}
194
208
  data-kind={kind}
195
209
  contentEditable={false}
@@ -199,10 +213,34 @@ export const testMetaBlock = createReactBlockSpec(
199
213
  <div className="bn-testmeta__header">
200
214
  <span className="bn-testmeta__label">{kind.toUpperCase()}</span>
201
215
  {idField?.value && <span className="bn-testmeta__id">{idField.value}</span>}
202
- <AddFieldMenu kind={kind} usedKeys={usedKeys} onPick={handleAddField} />
216
+ {!expanded && (
217
+ <button
218
+ type="button"
219
+ className="bn-testmeta__summary"
220
+ title={summaryText || "No metadata yet"}
221
+ onClick={() => setExpanded(true)}
222
+ >
223
+ {summaryText || <span className="bn-testmeta__summary--empty">No metadata</span>}
224
+ </button>
225
+ )}
226
+ <div className="bn-testmeta__actions">
227
+ {expanded && <AddFieldMenu kind={kind} usedKeys={usedKeys} onPick={handleAddField} />}
228
+ <button
229
+ type="button"
230
+ className={`bn-testmeta__toggle${expanded ? " bn-testmeta__toggle--expanded" : ""}`}
231
+ aria-expanded={expanded}
232
+ aria-label={expanded ? "Collapse metadata" : "Expand metadata"}
233
+ title={expanded ? "Collapse" : "Expand"}
234
+ onClick={() => setExpanded((prev) => !prev)}
235
+ >
236
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true">
237
+ <path d="M4 6L8 10L12 6" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
238
+ </svg>
239
+ </button>
240
+ </div>
203
241
  </div>
204
242
 
205
- {editableFields.length > 0 && (
243
+ {expanded && editableFields.length > 0 && (
206
244
  <div className="bn-testmeta__rows">
207
245
  {editableFields.map(({ field, index }) => (
208
246
  <div className="bn-testmeta__row" key={index}>
@@ -752,8 +752,69 @@ html.dark .bn-teststep__view-toggle--compact svg {
752
752
  margin-left: 8px;
753
753
  }
754
754
 
755
- .bn-testmeta__header .bn-testmeta__add-wrap {
755
+ /* Add button + expand/collapse toggle live in a right-pinned action group. */
756
+ .bn-testmeta__header .bn-testmeta__actions {
756
757
  margin-left: auto;
758
+ display: inline-flex;
759
+ align-items: center;
760
+ gap: 2px;
761
+ flex-shrink: 0;
762
+ }
763
+
764
+ /* Compact one-liner: the metadata rendered as truncated read text, click to
765
+ expand. Takes the remaining header width and ellipsizes when it overflows. */
766
+ .bn-testmeta__summary {
767
+ flex: 1 1 auto;
768
+ min-width: 0;
769
+ overflow: hidden;
770
+ white-space: nowrap;
771
+ text-overflow: ellipsis;
772
+ text-align: left;
773
+ font-family: inherit;
774
+ font-size: 13px;
775
+ color: var(--text-muted);
776
+ background: transparent;
777
+ border: none;
778
+ padding: 0;
779
+ cursor: pointer;
780
+ }
781
+
782
+ .bn-testmeta__summary:hover {
783
+ color: var(--text-primary);
784
+ }
785
+
786
+ .bn-testmeta__summary--empty {
787
+ font-style: italic;
788
+ opacity: 0.7;
789
+ }
790
+
791
+ .bn-testmeta__toggle {
792
+ width: 24px;
793
+ height: 24px;
794
+ display: inline-flex;
795
+ align-items: center;
796
+ justify-content: center;
797
+ color: var(--text-muted);
798
+ background: transparent;
799
+ border: none;
800
+ border-radius: 6px;
801
+ cursor: pointer;
802
+ padding: 0;
803
+ flex-shrink: 0;
804
+ transition: background-color 120ms ease;
805
+ }
806
+
807
+ .bn-testmeta__toggle:hover {
808
+ background: var(--step-bg-button-hover);
809
+ color: var(--text-primary);
810
+ }
811
+
812
+ .bn-testmeta__toggle svg {
813
+ transition: transform 150ms ease;
814
+ }
815
+
816
+ .bn-testmeta__toggle--expanded svg {
817
+ transform: rotate(180deg);
757
818
  }
758
819
 
759
820
  .bn-testmeta__label {