testomatio-editor-blocks 0.4.27 → 0.4.29
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.
- package/package/editor/blocks/step.d.ts +10 -0
- package/package/editor/blocks/step.js +62 -0
- package/package/editor/createMarkdownPasteHandler.js +16 -3
- package/package/index.d.ts +1 -1
- package/package/index.js +1 -1
- package/package.json +1 -1
- package/src/editor/blocks/step.tsx +66 -0
- package/src/editor/createMarkdownPasteHandler.ts +13 -0
- package/src/index.ts +1 -1
|
@@ -14,6 +14,16 @@ export declare const isEmptyParagraph: (b: any) => boolean;
|
|
|
14
14
|
export declare function canInsertStepOrSnippet(editor: {
|
|
15
15
|
document: any[];
|
|
16
16
|
}, referenceBlockId: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Programmatically add an empty step block to the editor.
|
|
19
|
+
* - If a "Steps" heading exists, inserts after the last step/snippet under it.
|
|
20
|
+
* - Otherwise, appends a "Steps" heading + empty step at the end.
|
|
21
|
+
* Returns the inserted step's block ID (for focusing), or null.
|
|
22
|
+
*/
|
|
23
|
+
export declare function addStepsBlock(editor: {
|
|
24
|
+
document: any[];
|
|
25
|
+
insertBlocks: (blocks: any[], referenceId: string, placement: string) => any[];
|
|
26
|
+
}): string | null;
|
|
17
27
|
export declare const stepBlock: {
|
|
18
28
|
config: {
|
|
19
29
|
readonly type: "testStep";
|
|
@@ -85,6 +85,62 @@ export function canInsertStepOrSnippet(editor, referenceBlockId) {
|
|
|
85
85
|
}
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Programmatically add an empty step block to the editor.
|
|
90
|
+
* - If a "Steps" heading exists, inserts after the last step/snippet under it.
|
|
91
|
+
* - Otherwise, appends a "Steps" heading + empty step at the end.
|
|
92
|
+
* Returns the inserted step's block ID (for focusing), or null.
|
|
93
|
+
*/
|
|
94
|
+
export function addStepsBlock(editor) {
|
|
95
|
+
var _a, _b, _c, _d;
|
|
96
|
+
const allBlocks = editor.document;
|
|
97
|
+
const emptyStep = {
|
|
98
|
+
type: "testStep",
|
|
99
|
+
props: { stepTitle: "", stepData: "", expectedResult: "" },
|
|
100
|
+
children: [],
|
|
101
|
+
};
|
|
102
|
+
let stepsHeadingIndex = -1;
|
|
103
|
+
for (let i = 0; i < allBlocks.length; i++) {
|
|
104
|
+
const b = allBlocks[i];
|
|
105
|
+
if (b.type !== "heading")
|
|
106
|
+
continue;
|
|
107
|
+
const text = (Array.isArray(b.content) ? b.content : [])
|
|
108
|
+
.filter((n) => n.type === "text")
|
|
109
|
+
.map((n) => { var _a; return (_a = n.text) !== null && _a !== void 0 ? _a : ""; })
|
|
110
|
+
.join("")
|
|
111
|
+
.trim()
|
|
112
|
+
.toLowerCase()
|
|
113
|
+
.replace(/[:\-–—]$/, "");
|
|
114
|
+
if (isStepsHeading(text)) {
|
|
115
|
+
stepsHeadingIndex = i;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (stepsHeadingIndex >= 0) {
|
|
120
|
+
let lastIndex = stepsHeadingIndex;
|
|
121
|
+
for (let i = stepsHeadingIndex + 1; i < allBlocks.length; i++) {
|
|
122
|
+
const b = allBlocks[i];
|
|
123
|
+
if (b.type === "testStep" || b.type === "snippet") {
|
|
124
|
+
lastIndex = i;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (isEmptyParagraph(b))
|
|
128
|
+
continue;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
const inserted = editor.insertBlocks([emptyStep], allBlocks[lastIndex].id, "after");
|
|
132
|
+
return (_b = (_a = inserted === null || inserted === void 0 ? void 0 : inserted[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
|
|
133
|
+
}
|
|
134
|
+
const lastBlock = allBlocks[allBlocks.length - 1];
|
|
135
|
+
const stepsHeading = {
|
|
136
|
+
type: "heading",
|
|
137
|
+
props: { level: 3 },
|
|
138
|
+
content: [{ type: "text", text: "Steps" }],
|
|
139
|
+
children: [],
|
|
140
|
+
};
|
|
141
|
+
const inserted = editor.insertBlocks([stepsHeading, emptyStep], lastBlock.id, "after");
|
|
142
|
+
return (_d = (_c = inserted === null || inserted === void 0 ? void 0 : inserted[1]) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : null;
|
|
143
|
+
}
|
|
88
144
|
export const stepBlock = createReactBlockSpec({
|
|
89
145
|
type: "testStep",
|
|
90
146
|
content: "none",
|
|
@@ -246,6 +302,12 @@ export const stepBlock = createReactBlockSpec({
|
|
|
246
302
|
});
|
|
247
303
|
}, [editor, block.id, expectedResult]);
|
|
248
304
|
const handleInsertNextStep = useCallback(() => {
|
|
305
|
+
const allBlocks = editor.document;
|
|
306
|
+
const idx = allBlocks.findIndex((b) => b.id === block.id);
|
|
307
|
+
const next = idx >= 0 ? allBlocks[idx + 1] : null;
|
|
308
|
+
if (next && isEmptyParagraph(next)) {
|
|
309
|
+
editor.removeBlocks([next.id]);
|
|
310
|
+
}
|
|
249
311
|
editor.insertBlocks([
|
|
250
312
|
{
|
|
251
313
|
type: "testStep",
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
export function createMarkdownPasteHandler(converter) {
|
|
2
2
|
return ({ event, editor, defaultPasteHandler }) => {
|
|
3
|
-
var _a, _b, _c, _d;
|
|
4
|
-
const
|
|
3
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4
|
+
const types = (_b = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : [];
|
|
5
|
+
if (types.includes("blocknote/html"))
|
|
6
|
+
return defaultPasteHandler();
|
|
7
|
+
if (types.includes("vscode-editor-data"))
|
|
8
|
+
return defaultPasteHandler();
|
|
9
|
+
if (types.includes("text/html")) {
|
|
10
|
+
const html = (_d = (_c = event.clipboardData) === null || _c === void 0 ? void 0 : _c.getData("text/html")) !== null && _d !== void 0 ? _d : "";
|
|
11
|
+
if (/<(pre|code)[\s>]/i.test(html))
|
|
12
|
+
return defaultPasteHandler();
|
|
13
|
+
}
|
|
14
|
+
const cursorBlock = editor.getTextCursorPosition().block;
|
|
15
|
+
if ((cursorBlock === null || cursorBlock === void 0 ? void 0 : cursorBlock.type) === "codeBlock" || (cursorBlock === null || cursorBlock === void 0 ? void 0 : cursorBlock.type) === "quote" || (cursorBlock === null || cursorBlock === void 0 ? void 0 : cursorBlock.type) === "table")
|
|
16
|
+
return defaultPasteHandler();
|
|
17
|
+
const plainText = (_f = (_e = event.clipboardData) === null || _e === void 0 ? void 0 : _e.getData("text/plain")) !== null && _f !== void 0 ? _f : "";
|
|
5
18
|
if (!plainText.trim())
|
|
6
19
|
return defaultPasteHandler();
|
|
7
20
|
try {
|
|
@@ -9,7 +22,7 @@ export function createMarkdownPasteHandler(converter) {
|
|
|
9
22
|
if (parsedBlocks.length === 0)
|
|
10
23
|
return defaultPasteHandler();
|
|
11
24
|
const selection = editor.getSelection();
|
|
12
|
-
const selectedIds = (
|
|
25
|
+
const selectedIds = (_h = (_g = selection === null || selection === void 0 ? void 0 : selection.blocks) === null || _g === void 0 ? void 0 : _g.map((block) => block.id).filter((id) => Boolean(id))) !== null && _h !== void 0 ? _h : [];
|
|
13
26
|
if (selectedIds.length > 0) {
|
|
14
27
|
editor.replaceBlocks(selectedIds, parsedBlocks);
|
|
15
28
|
}
|
package/package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { customSchema, type CustomSchema, type CustomBlock, type CustomEditor, } from "./editor/customSchema";
|
|
2
|
-
export { stepBlock, canInsertStepOrSnippet, isStepsHeading } from "./editor/blocks/step";
|
|
2
|
+
export { stepBlock, canInsertStepOrSnippet, isStepsHeading, addStepsBlock } 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, isStepsHeading } from "./editor/blocks/step";
|
|
2
|
+
export { stepBlock, canInsertStepOrSnippet, isStepsHeading, addStepsBlock } 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
|
@@ -96,6 +96,66 @@ export function canInsertStepOrSnippet(
|
|
|
96
96
|
return false;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Programmatically add an empty step block to the editor.
|
|
101
|
+
* - If a "Steps" heading exists, inserts after the last step/snippet under it.
|
|
102
|
+
* - Otherwise, appends a "Steps" heading + empty step at the end.
|
|
103
|
+
* Returns the inserted step's block ID (for focusing), or null.
|
|
104
|
+
*/
|
|
105
|
+
export function addStepsBlock(editor: {
|
|
106
|
+
document: any[];
|
|
107
|
+
insertBlocks: (blocks: any[], referenceId: string, placement: string) => any[];
|
|
108
|
+
}): string | null {
|
|
109
|
+
const allBlocks = editor.document;
|
|
110
|
+
const emptyStep = {
|
|
111
|
+
type: "testStep" as const,
|
|
112
|
+
props: { stepTitle: "", stepData: "", expectedResult: "" },
|
|
113
|
+
children: [],
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
let stepsHeadingIndex = -1;
|
|
117
|
+
for (let i = 0; i < allBlocks.length; i++) {
|
|
118
|
+
const b = allBlocks[i];
|
|
119
|
+
if (b.type !== "heading") continue;
|
|
120
|
+
const text = (Array.isArray(b.content) ? b.content : [])
|
|
121
|
+
.filter((n: any) => n.type === "text")
|
|
122
|
+
.map((n: any) => n.text ?? "")
|
|
123
|
+
.join("")
|
|
124
|
+
.trim()
|
|
125
|
+
.toLowerCase()
|
|
126
|
+
.replace(/[:\-–—]$/, "");
|
|
127
|
+
if (isStepsHeading(text)) {
|
|
128
|
+
stepsHeadingIndex = i;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (stepsHeadingIndex >= 0) {
|
|
134
|
+
let lastIndex = stepsHeadingIndex;
|
|
135
|
+
for (let i = stepsHeadingIndex + 1; i < allBlocks.length; i++) {
|
|
136
|
+
const b = allBlocks[i];
|
|
137
|
+
if (b.type === "testStep" || b.type === "snippet") {
|
|
138
|
+
lastIndex = i;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (isEmptyParagraph(b)) continue;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
const inserted = editor.insertBlocks([emptyStep], allBlocks[lastIndex].id, "after");
|
|
145
|
+
return inserted?.[0]?.id ?? null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const lastBlock = allBlocks[allBlocks.length - 1];
|
|
149
|
+
const stepsHeading = {
|
|
150
|
+
type: "heading" as const,
|
|
151
|
+
props: { level: 3 },
|
|
152
|
+
content: [{ type: "text" as const, text: "Steps" }],
|
|
153
|
+
children: [],
|
|
154
|
+
};
|
|
155
|
+
const inserted = editor.insertBlocks([stepsHeading, emptyStep], lastBlock.id, "after");
|
|
156
|
+
return inserted?.[1]?.id ?? null;
|
|
157
|
+
}
|
|
158
|
+
|
|
99
159
|
export const stepBlock = createReactBlockSpec(
|
|
100
160
|
{
|
|
101
161
|
type: "testStep",
|
|
@@ -287,6 +347,12 @@ export const stepBlock = createReactBlockSpec(
|
|
|
287
347
|
);
|
|
288
348
|
|
|
289
349
|
const handleInsertNextStep = useCallback(() => {
|
|
350
|
+
const allBlocks = editor.document;
|
|
351
|
+
const idx = allBlocks.findIndex((b: any) => b.id === block.id);
|
|
352
|
+
const next = idx >= 0 ? allBlocks[idx + 1] : null;
|
|
353
|
+
if (next && isEmptyParagraph(next)) {
|
|
354
|
+
editor.removeBlocks([next.id]);
|
|
355
|
+
}
|
|
290
356
|
editor.insertBlocks(
|
|
291
357
|
[
|
|
292
358
|
{
|
|
@@ -14,6 +14,19 @@ export function createMarkdownPasteHandler(
|
|
|
14
14
|
converter: (markdown: string) => CustomPartialBlock[],
|
|
15
15
|
) {
|
|
16
16
|
return ({ event, editor, defaultPasteHandler }: PasteHandlerContext): boolean | undefined => {
|
|
17
|
+
const types = event.clipboardData?.types ?? [];
|
|
18
|
+
|
|
19
|
+
if (types.includes("blocknote/html")) return defaultPasteHandler();
|
|
20
|
+
if (types.includes("vscode-editor-data")) return defaultPasteHandler();
|
|
21
|
+
|
|
22
|
+
if (types.includes("text/html")) {
|
|
23
|
+
const html = event.clipboardData?.getData("text/html") ?? "";
|
|
24
|
+
if (/<(pre|code)[\s>]/i.test(html)) return defaultPasteHandler();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const cursorBlock = editor.getTextCursorPosition().block;
|
|
28
|
+
if (cursorBlock?.type === "codeBlock" || cursorBlock?.type === "quote" || cursorBlock?.type === "table") return defaultPasteHandler();
|
|
29
|
+
|
|
17
30
|
const plainText = event.clipboardData?.getData("text/plain") ?? "";
|
|
18
31
|
if (!plainText.trim()) return defaultPasteHandler();
|
|
19
32
|
|
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, isStepsHeading } from "./editor/blocks/step";
|
|
7
|
+
export { stepBlock, canInsertStepOrSnippet, isStepsHeading, addStepsBlock } from "./editor/blocks/step";
|
|
8
8
|
export { snippetBlock } from "./editor/blocks/snippet";
|
|
9
9
|
export { markdownToHtml, htmlToMarkdown } from "./editor/blocks/markdown";
|
|
10
10
|
|