Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

## 0.4.93

- Test and suite header is a card that folds open: `Test` / `Suite` label, id, first field and `+N` when shut, `No details` when empty, `+` adds a field. It is read-only when the editor is not editable.
- `TestMetaCard` is exported for read-only views.
- New `--tme-*` theme tokens for every color, font and size. Defaults keep the Testomat.io look. Most `html.dark` overrides moved into the tokens.
- New headless entry `testomatio-editor-blocks/markdown`: `parseTestDocument`, `metaFieldValue`, `scanMarkdownBlocks`, `splitTags` plus the converters, with no React or BlockNote at runtime.
- Header markup changed: `.bn-testmeta__summary` is a span inside `.bn-testmeta__trigger`; `.bn-testmeta--expanded/--collapsed` became `.bn-testmeta--open`; `.bn-testmeta__toggle` became `.bn-testmeta__chevron`; `.bn-testmeta__key--input` was folded into `.bn-testmeta__key`.
- Dark mode: a few near-identical greys were merged (step preview text, snippet chevron, link tooltip url).
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,68 @@ return (

Step and snippet fields inherit the browser's `spellcheck` setting from the editor container, so it is enabled by default. To turn it off for the whole editor (paragraphs and steps), set `spellcheck="false"` on any wrapper around `BlockNoteView`.

## Test and Suite Header

`<!-- test -->` and `<!-- suite -->` comments render as a card that folds open into their fields. Shut, it shows the id, the first filled field and how many more. The `+` button adds a field from `getMetaFieldSuggestions`. The card is read-only when the editor is not editable.

The same card is exported for read-only views outside the editor:

```tsx
import { TestMetaCard } from "testomatio-editor-blocks";

<TestMetaCard kind="test" fields={[{ key: "id", value: "@T1234abcd" }]} onChange={() => {}} readOnly />
```

## Theming

Every color, font and size comes from a `--tme-*` token. Defaults are the Testomat.io look. Set the tokens on any ancestor of the editor (or `:root`) to restyle it. Dark values switch on `html.dark`.

| Token | Default (light) | Used for |
| --- | --- | --- |
| `--tme-font-sans` / `--tme-font-mono` | Inter / system mono | Text / ids |
| `--tme-text-size` / `--tme-leading` | 14px / 20px | Step fields |
| `--tme-h1` … `--tme-h6` | 22 / 20 / 18 / 16 / 14 / 14px | Headings |
| `--tme-fg` | #262626 | Text |
| `--tme-fg-strong` / `--tme-fg-soft` | #0a0a0a / #404040 | Icons / step buttons |
| `--tme-muted-fg` / `--tme-placeholder` | #737373 / #a1a1a1 | Labels / placeholders |
| `--tme-border` / `--tme-border-strong` | #e5e5e5 / #d4d4d4 | Borders |
| `--tme-surface` / `--tme-surface-hover` | #fff / #fafafa | Popovers, menus |
| `--tme-muted` | slate 5% | Soft fills |
| `--tme-primary` / `--tme-ring` | #4f46e5 / its 25% | Focus, open card |
| `--tme-link` / `--tme-code` / `--tme-danger` | indigo / amber / red | Links / code / remove |
| `--tme-tooltip-bg` / `--tme-tooltip-fg` | #0a0a0a / #fafafa | Tooltips |
| `--tme-shadow` / `--tme-radius` | 12% black / 8px | Popovers / corners |
| `--tme-meta-bg` / `--tme-meta-border` / `--tme-meta-border-open` | muted / border / primary 50% | Test and suite header |
| `--tme-meta-gap` | 2rem | Space above each test |

Step and snippet blocks also keep their older `--step-*` and `--snippet-*` variables.

```css
.my-editor {
--tme-font-sans: var(--font-sans);
--tme-fg: var(--foreground);
--tme-primary: var(--primary);
}
```

## Headless Parser

`testomatio-editor-blocks/markdown` holds the Markdown parser and serializer without React, BlockNote or a DOM, so a server can read test files with the same rules as the editor.

```ts
import { parseTestDocument, metaFieldValue, splitTags } from "testomatio-editor-blocks/markdown";

for (const section of parseTestDocument(markdown)) {
// section.meta: { kind: "test" | "suite", fields, inline } | null
// section.start / bodyStart / end: 0-based lines, end exclusive
// section.heading: the first # or ## heading; section.steps: { title, data, expected }
const id = metaFieldValue(section.meta, "id");
const { title, tags } = splitTags(section.heading?.text ?? "");
}
```

It also exports `markdownToBlocks`, `blocksToMarkdown`, `scanMarkdownBlocks` (blocks with their source lines), `isStepsHeading` and `getMetaFieldSuggestions`.

## Step Autocomplete & Image Upload Hooks

Configure everything via JS—no React providers required:
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "testomatio-editor-blocks",
"version": "0.4.82",
"version": "0.4.93",
"description": "Custom BlockNote schema, markdown conversion helpers, and UI for Testomatio-style test cases and steps.",
"type": "module",
"main": "./package/index.js",
Expand All @@ -15,6 +15,10 @@
"types": "./package/snippets.d.ts",
"import": "./package/snippets.js"
},
"./markdown": {
"types": "./package/markdown.d.ts",
"import": "./package/markdown.js"
},
"./styles.css": "./package/styles.css",
"./package.json": "./package.json"
},
Expand Down
21 changes: 20 additions & 1 deletion src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@

.app__header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-start;
gap: 1.5rem;
}

.app__intro {
flex: 1 1 32rem;
}

.app__actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
flex-shrink: 0;
}

.app__header h1 {
Expand Down Expand Up @@ -350,3 +355,17 @@ html.dark .app__copy-status {
grid-template-columns: 1fr;
}
}

/* A sample host theme: the editor restyled only through --tme-* tokens. */
.app__editor--custom-theme {
--tme-font-sans: Georgia, serif;
--tme-fg: #1e1b4b;
--tme-muted-fg: #6d28d9;
--tme-primary: #7c3aed;
--tme-link: #7c3aed;
--tme-meta-bg: #f5f3ff;
--tme-meta-border: #ddd6fe;
--tme-radius: 12px;
--tme-h1: 28px;
--tme-h2: 24px;
}
12 changes: 10 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ function App() {
"idle",
);
const [darkMode, setDarkMode] = useState(false);
const [customTheme, setCustomTheme] = useState(false);
const [suggestWhileTyping, setSuggestWhileTyping] = useState(true);
const [markdownInput, setMarkdownInput] = useState("");
const [inputError, setInputError] = useState<string | null>(null);
Expand Down Expand Up @@ -748,7 +749,7 @@ function App() {
return (
<div className="app">
<header className="app__header">
<div>
<div className="app__intro">
<h1>BlockNote Custom Block Playground</h1>
<p>
Explore custom blocks for documenting test cases and actionable steps, then convert the document to Markdown using a bespoke serializer.
Expand Down Expand Up @@ -779,6 +780,13 @@ function App() {
>
Suggest while typing: {suggestWhileTyping ? "on" : "off"}
</button>
<button
type="button"
className="app__action app__action--ghost"
onClick={() => setCustomTheme((v) => !v)}
>
Theme: {customTheme ? "custom" : "Testomat.io"}
</button>
<button
type="button"
className="app__dark-toggle"
Expand All @@ -796,7 +804,7 @@ function App() {

<section className="app__workspace">
<div
className="app__editor"
className={`app__editor${customTheme ? " app__editor--custom-theme" : ""}`}
data-step-autocomplete={suggestWhileTyping ? "true" : "false"}
>
<BlockNoteView
Expand Down
10 changes: 2 additions & 8 deletions src/editor/blocks/step.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StepHorizontalView } from "./stepHorizontalView";
import { useStepImageUpload } from "../stepImageUpload";
import { isSuiteDocument } from "../exampleTableHighlight";
import type { StepSuggestion } from "../stepAutocomplete";
import { isStepsHeading } from "../stepsHeading";

const EXPECTED_COLLAPSED_KEY = "bn-expected-collapsed";
const VIEW_MODE_KEY = "bn-step-view-mode";
Expand Down Expand Up @@ -80,14 +81,7 @@ function useStepViewMode(): StepViewMode {
return viewMode;
}

/**
* Returns true when a normalised (lowercased, trailing-punctuation-stripped)
* heading text looks like a "Steps" heading.
* Accepted forms: steps, step, step(s), test steps, test step, test step(s).
*/
export function isStepsHeading(text: string): boolean {
return /^(test\s+)?step(s|\(s\))?$/.test(text);
}
export { isStepsHeading };

export const isEmptyParagraph = (b: any): boolean =>
b.type === "paragraph" &&
Expand Down
Loading
Loading