testomatio-editor-blocks 0.2.3 → 0.4.0
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/markdown.d.ts +5 -0
- package/package/editor/blocks/markdown.js +30 -5
- package/package/editor/blocks/snippet.js +127 -2
- package/package/editor/blocks/step.js +82 -15
- package/package/editor/blocks/stepField.d.ts +7 -3
- package/package/editor/blocks/stepField.js +395 -230
- package/package/editor/blocks/useAutoResize.d.ts +8 -0
- package/package/editor/blocks/useAutoResize.js +31 -0
- package/package/editor/customMarkdownConverter.js +150 -21
- package/package/styles.css +327 -71
- package/package.json +5 -2
- package/src/App.tsx +1 -1
- package/src/editor/blocks/markdown.ts +35 -5
- package/src/editor/blocks/snippet.tsx +202 -26
- package/src/editor/blocks/step.tsx +132 -36
- package/src/editor/blocks/stepField.tsx +552 -267
- package/src/editor/blocks/useAutoResize.ts +44 -0
- package/src/editor/customMarkdownConverter.test.ts +114 -2
- package/src/editor/customMarkdownConverter.ts +166 -19
- package/src/editor/customSchema.test.ts +35 -0
- package/src/editor/markdownToBlocks.test.ts +119 -0
- package/src/editor/styles.css +342 -71
|
@@ -3,3 +3,8 @@ export declare function markdownToHtml(markdown: string): string;
|
|
|
3
3
|
export declare function escapeMarkdownText(text: string): string;
|
|
4
4
|
export declare function normalizePlainText(text: string): string;
|
|
5
5
|
export declare function htmlToMarkdown(html: string): string;
|
|
6
|
+
declare function cleanupEscapedFormatting(markdown: string): string;
|
|
7
|
+
export declare const __markdownStringUtils: {
|
|
8
|
+
cleanupEscapedFormatting: typeof cleanupEscapedFormatting;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const IMAGE_MARKDOWN_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
2
2
|
const MARKDOWN_ESCAPE_REGEX = /([*_\\])/g;
|
|
3
|
+
const INLINE_SEGMENT_REGEX = /(\*\*\*[^*]+\*\*\*|___[^_]+___|\*\*[^*]+\*\*|__[^_]+__|\*[^*]+\*|_[^_]+_|<u>[^<]+<\/u>)/;
|
|
3
4
|
export function escapeHtml(text) {
|
|
4
5
|
return text
|
|
5
6
|
.replace(/&/g, "&")
|
|
@@ -16,11 +17,16 @@ function parseInlineMarkdown(text) {
|
|
|
16
17
|
return [];
|
|
17
18
|
}
|
|
18
19
|
const normalized = text.replace(/\\([*_`~])/g, "\uE000$1");
|
|
19
|
-
const rawSegments = normalized
|
|
20
|
-
.split(/(\*\*[^*]+\*\*|__[^_]+__|\*[^*]+\*|_[^_]+_|<u>[^<]+<\/u>)/)
|
|
21
|
-
.filter(Boolean);
|
|
20
|
+
const rawSegments = normalized.split(INLINE_SEGMENT_REGEX).filter(Boolean);
|
|
22
21
|
return rawSegments.map((segment) => {
|
|
23
22
|
const baseStyles = { bold: false, italic: false, underline: false };
|
|
23
|
+
if (/^\*\*\*(.+)\*\*\*$/.test(segment) || /^___(.+)___$/.test(segment)) {
|
|
24
|
+
const content = segment.slice(3, -3);
|
|
25
|
+
return {
|
|
26
|
+
text: restoreEscapes(content),
|
|
27
|
+
styles: { bold: true, italic: true, underline: false },
|
|
28
|
+
};
|
|
29
|
+
}
|
|
24
30
|
if (/^\*\*(.+)\*\*$/.test(segment) || /^__(.+)__$/.test(segment)) {
|
|
25
31
|
const content = segment.slice(2, -2);
|
|
26
32
|
return {
|
|
@@ -106,12 +112,13 @@ function fallbackHtmlToMarkdown(html) {
|
|
|
106
112
|
.replace(/<\/span>/gi, "")
|
|
107
113
|
.replace(/<u>(.*?)<\/u>/gis, (_m, content) => `<u>${content}</u>`);
|
|
108
114
|
result = result.replace(/<\/?[^>]+>/g, "");
|
|
109
|
-
|
|
115
|
+
const markdown = result
|
|
110
116
|
.split("\n")
|
|
111
117
|
.map((line) => line.trimEnd())
|
|
112
118
|
.join("\n")
|
|
113
119
|
.replace(/\n{3,}/g, "\n\n")
|
|
114
120
|
.trim();
|
|
121
|
+
return cleanupEscapedFormatting(markdown);
|
|
115
122
|
}
|
|
116
123
|
export function htmlToMarkdown(html) {
|
|
117
124
|
if (typeof document === "undefined") {
|
|
@@ -156,5 +163,23 @@ export function htmlToMarkdown(html) {
|
|
|
156
163
|
}
|
|
157
164
|
};
|
|
158
165
|
const markdown = Array.from(temp.childNodes).map(traverse).join("");
|
|
159
|
-
return markdown.replace(/\n{3,}/g, "\n\n").trim();
|
|
166
|
+
return cleanupEscapedFormatting(markdown).replace(/\n{3,}/g, "\n\n").trim();
|
|
167
|
+
}
|
|
168
|
+
function cleanupEscapedFormatting(markdown) {
|
|
169
|
+
return markdown.replace(/(\\+)([*_]+)/g, (_match, slashes, markers) => {
|
|
170
|
+
if (markers.length === 0) {
|
|
171
|
+
return slashes + markers;
|
|
172
|
+
}
|
|
173
|
+
const shouldClean = markers.length === 3 ||
|
|
174
|
+
markers.length === 2 ||
|
|
175
|
+
markers.length === 1;
|
|
176
|
+
if (!shouldClean) {
|
|
177
|
+
return slashes + markers;
|
|
178
|
+
}
|
|
179
|
+
const hasPrintable = slashes.length % 2 === 0;
|
|
180
|
+
return hasPrintable ? markers : slashes + markers;
|
|
181
|
+
});
|
|
160
182
|
}
|
|
183
|
+
export const __markdownStringUtils = {
|
|
184
|
+
cleanupEscapedFormatting,
|
|
185
|
+
};
|
|
@@ -1,8 +1,131 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createReactBlockSpec } from "@blocknote/react";
|
|
3
|
-
import
|
|
3
|
+
import OverType from "overtype";
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
5
|
import { StepField } from "./stepField";
|
|
5
6
|
import { useSnippetAutocomplete } from "../snippetAutocomplete";
|
|
7
|
+
import { useStepImageUpload } from "../stepImageUpload";
|
|
8
|
+
function SnippetDataField({ label, value, placeholder, onChange, onFieldFocus, fieldName, enableImageUpload = false, }) {
|
|
9
|
+
const containerRef = useRef(null);
|
|
10
|
+
const instanceRef = useRef(null);
|
|
11
|
+
const uploadImage = useStepImageUpload();
|
|
12
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
13
|
+
const onChangeRef = useRef(onChange);
|
|
14
|
+
const initialValueRef = useRef(value);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
onChangeRef.current = onChange;
|
|
17
|
+
}, [onChange]);
|
|
18
|
+
const insertImageMarkdown = useCallback((url) => {
|
|
19
|
+
var _a, _b, _c;
|
|
20
|
+
const instance = instanceRef.current;
|
|
21
|
+
const textarea = instance === null || instance === void 0 ? void 0 : instance.textarea;
|
|
22
|
+
if (!instance || !textarea) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const currentValue = instance.getValue();
|
|
26
|
+
const selectionStart = (_a = textarea.selectionStart) !== null && _a !== void 0 ? _a : currentValue.length;
|
|
27
|
+
const selectionEnd = (_b = textarea.selectionEnd) !== null && _b !== void 0 ? _b : currentValue.length;
|
|
28
|
+
const before = currentValue.slice(0, selectionStart);
|
|
29
|
+
const after = currentValue.slice(selectionEnd);
|
|
30
|
+
const needsNewlineBefore = before.length > 0 && !before.endsWith("\n");
|
|
31
|
+
const needsNewlineAfter = after.length > 0 && !after.startsWith("\n");
|
|
32
|
+
const markdown = `${needsNewlineBefore ? "\n" : ""}${needsNewlineAfter ? "\n" : ""}`;
|
|
33
|
+
const nextValue = `${before}${markdown}${after}`;
|
|
34
|
+
instance.setValue(nextValue);
|
|
35
|
+
(_c = onChangeRef.current) === null || _c === void 0 ? void 0 : _c.call(onChangeRef, nextValue);
|
|
36
|
+
requestAnimationFrame(() => {
|
|
37
|
+
const cursor = selectionStart + markdown.length;
|
|
38
|
+
textarea.selectionStart = cursor;
|
|
39
|
+
textarea.selectionEnd = cursor;
|
|
40
|
+
textarea.focus();
|
|
41
|
+
});
|
|
42
|
+
}, []);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const container = containerRef.current;
|
|
45
|
+
if (!container) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const [instance] = OverType.init(container, {
|
|
49
|
+
value: initialValueRef.current,
|
|
50
|
+
placeholder,
|
|
51
|
+
autoResize: true,
|
|
52
|
+
minHeight: "5rem",
|
|
53
|
+
toolbar: false,
|
|
54
|
+
onChange: (nextValue) => {
|
|
55
|
+
var _a;
|
|
56
|
+
(_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, nextValue);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
instanceRef.current = instance;
|
|
60
|
+
const textarea = instance.textarea;
|
|
61
|
+
if (fieldName) {
|
|
62
|
+
textarea.dataset.stepField = fieldName;
|
|
63
|
+
}
|
|
64
|
+
const handleFocus = () => {
|
|
65
|
+
setIsFocused(true);
|
|
66
|
+
onFieldFocus === null || onFieldFocus === void 0 ? void 0 : onFieldFocus();
|
|
67
|
+
};
|
|
68
|
+
const handleBlur = () => setIsFocused(false);
|
|
69
|
+
textarea.addEventListener("focus", handleFocus);
|
|
70
|
+
textarea.addEventListener("blur", handleBlur);
|
|
71
|
+
return () => {
|
|
72
|
+
textarea.removeEventListener("focus", handleFocus);
|
|
73
|
+
textarea.removeEventListener("blur", handleBlur);
|
|
74
|
+
instance.destroy();
|
|
75
|
+
instanceRef.current = null;
|
|
76
|
+
};
|
|
77
|
+
}, [fieldName, onFieldFocus, placeholder]);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const instance = instanceRef.current;
|
|
80
|
+
if (!instance) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (instance.getValue() !== value) {
|
|
84
|
+
instance.setValue(value);
|
|
85
|
+
}
|
|
86
|
+
}, [value]);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
var _a;
|
|
89
|
+
if (!enableImageUpload || !uploadImage) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const textarea = (_a = instanceRef.current) === null || _a === void 0 ? void 0 : _a.textarea;
|
|
93
|
+
if (!textarea) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const handlePaste = async (event) => {
|
|
97
|
+
var _a, _b;
|
|
98
|
+
const items = Array.from((_b = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
|
|
99
|
+
const imageItem = items.find((item) => item.kind === "file" && item.type.startsWith("image/"));
|
|
100
|
+
const file = imageItem === null || imageItem === void 0 ? void 0 : imageItem.getAsFile();
|
|
101
|
+
if (!file) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
try {
|
|
106
|
+
const response = await uploadImage(file);
|
|
107
|
+
if (response === null || response === void 0 ? void 0 : response.url) {
|
|
108
|
+
insertImageMarkdown(response.url);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error("Failed to upload pasted image", error);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
textarea.addEventListener("paste", handlePaste);
|
|
116
|
+
return () => {
|
|
117
|
+
textarea.removeEventListener("paste", handlePaste);
|
|
118
|
+
};
|
|
119
|
+
}, [enableImageUpload, insertImageMarkdown, uploadImage]);
|
|
120
|
+
const editorClassName = useMemo(() => [
|
|
121
|
+
"bn-step-editor",
|
|
122
|
+
"bn-step-editor--multiline",
|
|
123
|
+
isFocused ? "bn-step-editor--focused" : "",
|
|
124
|
+
]
|
|
125
|
+
.filter(Boolean)
|
|
126
|
+
.join(" "), [isFocused]);
|
|
127
|
+
return (_jsxs("div", { className: "bn-step-field", children: [_jsx("div", { className: "bn-step-field__top", children: _jsx("span", { className: "bn-step-field__label", children: label }) }), _jsx("div", { ref: containerRef, className: editorClassName, "data-step-field": fieldName })] }));
|
|
128
|
+
}
|
|
6
129
|
export const snippetBlock = createReactBlockSpec({
|
|
7
130
|
type: "snippet",
|
|
8
131
|
content: "none",
|
|
@@ -24,8 +147,10 @@ export const snippetBlock = createReactBlockSpec({
|
|
|
24
147
|
render: ({ block, editor }) => {
|
|
25
148
|
const snippetTitle = block.props.snippetTitle || "";
|
|
26
149
|
const snippetData = block.props.snippetData || "";
|
|
150
|
+
const snippetId = block.props.snippetId || "";
|
|
27
151
|
const snippetSuggestions = useSnippetAutocomplete();
|
|
28
152
|
const hasSnippets = snippetSuggestions.length > 0;
|
|
153
|
+
const isSnippetSelected = snippetId.length > 0;
|
|
29
154
|
const handleSnippetChange = useCallback((nextTitle) => {
|
|
30
155
|
if (nextTitle === snippetTitle) {
|
|
31
156
|
return;
|
|
@@ -67,6 +192,6 @@ export const snippetBlock = createReactBlockSpec({
|
|
|
67
192
|
if (!hasSnippets) {
|
|
68
193
|
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." }) }));
|
|
69
194
|
}
|
|
70
|
-
return (
|
|
195
|
+
return (_jsx("div", { className: "bn-teststep bn-snippet", "data-block-id": block.id, children: !isSnippetSelected ? (_jsx(StepField, { label: "Snippet Title", value: snippetTitle, onChange: handleSnippetChange, autoFocus: snippetTitle.length === 0, enableAutocomplete: true, suggestionFilter: (suggestion) => suggestion.isSnippet === true, suggestionsOverride: snippetSuggestions, onSuggestionSelect: handleSnippetSelect, fieldName: "snippet-title", showSuggestionsOnFocus: true, enableImageUpload: false, onFieldFocus: handleFieldFocus, readOnly: false })) : (_jsx(SnippetDataField, { label: `Snippet: ${snippetTitle}`, value: snippetData, onChange: handleSnippetDataChange, fieldName: "snippet-data", enableImageUpload: true, onFieldFocus: handleFieldFocus, placeholder: "Snippet data will appear here..." })) }));
|
|
71
196
|
},
|
|
72
197
|
});
|
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createReactBlockSpec } from "@blocknote/react";
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { StepField } from "./stepField";
|
|
5
5
|
import { useStepImageUpload } from "../stepImageUpload";
|
|
6
|
+
const EXPECTED_COLLAPSED_KEY = "bn-expected-collapsed";
|
|
7
|
+
const readExpectedCollapsedPreference = () => {
|
|
8
|
+
if (typeof window === "undefined") {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
return window.localStorage.getItem(EXPECTED_COLLAPSED_KEY) === "true";
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const writeExpectedCollapsedPreference = (collapsed) => {
|
|
19
|
+
if (typeof window === "undefined") {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
window.localStorage.setItem(EXPECTED_COLLAPSED_KEY, collapsed ? "true" : "false");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
//
|
|
27
|
+
}
|
|
28
|
+
};
|
|
6
29
|
export const stepBlock = createReactBlockSpec({
|
|
7
30
|
type: "testStep",
|
|
8
31
|
content: "none",
|
|
@@ -22,22 +45,25 @@ export const stepBlock = createReactBlockSpec({
|
|
|
22
45
|
const stepTitle = block.props.stepTitle || "";
|
|
23
46
|
const stepData = block.props.stepData || "";
|
|
24
47
|
const expectedResult = block.props.expectedResult || "";
|
|
25
|
-
const
|
|
26
|
-
const
|
|
48
|
+
const expectedHasContent = expectedResult.trim().length > 0;
|
|
49
|
+
const storedExpectedCollapsed = useMemo(() => readExpectedCollapsedPreference(), []);
|
|
50
|
+
const dataHasContent = stepData.trim().length > 0;
|
|
51
|
+
const [isExpectedVisible, setIsExpectedVisible] = useState(expectedHasContent ? true : !storedExpectedCollapsed);
|
|
52
|
+
const [isDataVisible, setIsDataVisible] = useState(dataHasContent);
|
|
27
53
|
const [shouldFocusDataField, setShouldFocusDataField] = useState(false);
|
|
28
54
|
const uploadImage = useStepImageUpload();
|
|
55
|
+
// Calculate step number based on position in document
|
|
56
|
+
const stepNumber = useMemo(() => {
|
|
57
|
+
const allBlocks = editor.document;
|
|
58
|
+
const stepBlocks = allBlocks.filter((b) => b.type === "testStep");
|
|
59
|
+
const index = stepBlocks.findIndex((b) => b.id === block.id);
|
|
60
|
+
return index >= 0 ? index + 1 : 1;
|
|
61
|
+
}, [editor.document, block.id]);
|
|
29
62
|
useEffect(() => {
|
|
30
|
-
if (
|
|
63
|
+
if (dataHasContent && !isDataVisible) {
|
|
31
64
|
setIsDataVisible(true);
|
|
32
65
|
}
|
|
33
|
-
}, [
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (shouldFocusDataField && isDataVisible) {
|
|
36
|
-
const timer = setTimeout(() => setShouldFocusDataField(false), 0);
|
|
37
|
-
return () => clearTimeout(timer);
|
|
38
|
-
}
|
|
39
|
-
return undefined;
|
|
40
|
-
}, [isDataVisible, shouldFocusDataField]);
|
|
66
|
+
}, [dataHasContent, isDataVisible]);
|
|
41
67
|
const handleStepTitleChange = useCallback((next) => {
|
|
42
68
|
if (next === stepTitle) {
|
|
43
69
|
return;
|
|
@@ -58,10 +84,13 @@ export const stepBlock = createReactBlockSpec({
|
|
|
58
84
|
},
|
|
59
85
|
});
|
|
60
86
|
}, [editor, block.id, stepData]);
|
|
61
|
-
const
|
|
87
|
+
const handleShowData = useCallback(() => {
|
|
62
88
|
setIsDataVisible(true);
|
|
63
89
|
setShouldFocusDataField(true);
|
|
64
90
|
}, []);
|
|
91
|
+
const handleHideData = useCallback(() => {
|
|
92
|
+
setIsDataVisible(false);
|
|
93
|
+
}, []);
|
|
65
94
|
const handleExpectedChange = useCallback((next) => {
|
|
66
95
|
if (next === expectedResult) {
|
|
67
96
|
return;
|
|
@@ -88,7 +117,25 @@ export const stepBlock = createReactBlockSpec({
|
|
|
88
117
|
const handleFieldFocus = useCallback(() => {
|
|
89
118
|
editor.setSelection(block.id, block.id);
|
|
90
119
|
}, [editor, block.id]);
|
|
91
|
-
|
|
120
|
+
const [dataFocusSignal] = useState(0);
|
|
121
|
+
const [expectedFocusSignal, setExpectedFocusSignal] = useState(0);
|
|
122
|
+
const handleShowExpected = useCallback(() => {
|
|
123
|
+
setIsExpectedVisible(true);
|
|
124
|
+
setExpectedFocusSignal((value) => value + 1);
|
|
125
|
+
writeExpectedCollapsedPreference(false);
|
|
126
|
+
}, []);
|
|
127
|
+
const handleHideExpected = useCallback(() => {
|
|
128
|
+
setIsExpectedVisible(false);
|
|
129
|
+
writeExpectedCollapsedPreference(true);
|
|
130
|
+
}, []);
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
if (expectedHasContent && !isExpectedVisible) {
|
|
133
|
+
setIsExpectedVisible(true);
|
|
134
|
+
}
|
|
135
|
+
}, [expectedHasContent, isExpectedVisible]);
|
|
136
|
+
const canToggleData = !dataHasContent;
|
|
137
|
+
const canToggleExpected = !expectedHasContent;
|
|
138
|
+
return (_jsxs("div", { className: "bn-teststep", "data-block-id": block.id, children: [_jsx(StepField, { label: `Step ${stepNumber}`, value: stepTitle, onChange: handleStepTitleChange, autoFocus: stepTitle.length === 0, enableAutocomplete: true, fieldName: "title", suggestionFilter: (suggestion) => suggestion.isSnippet !== true, onFieldFocus: handleFieldFocus, enableImageUpload: false, showFormattingButtons: true, onImageFile: async (file) => {
|
|
92
139
|
if (!uploadImage) {
|
|
93
140
|
return;
|
|
94
141
|
}
|
|
@@ -108,6 +155,26 @@ export const stepBlock = createReactBlockSpec({
|
|
|
108
155
|
catch (error) {
|
|
109
156
|
console.error("Failed to upload image to Step Data", error);
|
|
110
157
|
}
|
|
111
|
-
} }), isDataVisible
|
|
158
|
+
} }), isDataVisible ? (_jsx(StepField, { label: "Step Data", labelToggle: canToggleData
|
|
159
|
+
? {
|
|
160
|
+
onClick: handleHideData,
|
|
161
|
+
expanded: true,
|
|
162
|
+
}
|
|
163
|
+
: undefined, value: stepData, onChange: handleStepDataChange, autoFocus: shouldFocusDataField, focusSignal: dataFocusSignal, multiline: true, enableImageUpload: true, showFormattingButtons: true, showImageButton: true, onFieldFocus: handleFieldFocus })) : (_jsx("div", { className: "bn-step-field bn-step-field--collapsed", children: _jsx("span", { className: "bn-step-field__label bn-step-field__label--toggle", role: "button", tabIndex: -1, onClick: handleShowData, onKeyDown: (event) => {
|
|
164
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
handleShowData();
|
|
167
|
+
}
|
|
168
|
+
}, "aria-expanded": "false", children: "Step Data" }) })), isExpectedVisible ? (_jsx(StepField, { label: "Expected Result", labelToggle: canToggleExpected
|
|
169
|
+
? {
|
|
170
|
+
onClick: handleHideExpected,
|
|
171
|
+
expanded: true,
|
|
172
|
+
}
|
|
173
|
+
: undefined, value: expectedResult, onChange: handleExpectedChange, multiline: true, focusSignal: expectedFocusSignal, enableImageUpload: true, showFormattingButtons: true, showImageButton: true, onFieldFocus: handleFieldFocus })) : (_jsx("div", { className: "bn-step-field bn-step-field--collapsed", children: _jsx("span", { className: "bn-step-field__label bn-step-field__label--toggle", role: "button", tabIndex: -1, onClick: handleShowExpected, onKeyDown: (event) => {
|
|
174
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
handleShowExpected();
|
|
177
|
+
}
|
|
178
|
+
}, "aria-expanded": "false", children: "Expected Result" }) })), _jsx("button", { type: "button", className: "bn-step-add", onClick: handleInsertNextStep, children: "+ Step" })] }));
|
|
112
179
|
},
|
|
113
180
|
});
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import { type StepSuggestion } from "../stepAutocomplete";
|
|
2
3
|
import { type SnippetSuggestion } from "../snippetAutocomplete";
|
|
3
|
-
import type { ReactNode } from "react";
|
|
4
4
|
type Suggestion = StepSuggestion | SnippetSuggestion;
|
|
5
5
|
type StepFieldProps = {
|
|
6
6
|
label: string;
|
|
7
|
+
labelToggle?: {
|
|
8
|
+
onClick: () => void;
|
|
9
|
+
expanded: boolean;
|
|
10
|
+
};
|
|
7
11
|
value: string;
|
|
8
|
-
placeholder: string;
|
|
9
12
|
onChange: (nextValue: string) => void;
|
|
10
13
|
autoFocus?: boolean;
|
|
14
|
+
focusSignal?: number;
|
|
11
15
|
multiline?: boolean;
|
|
12
16
|
enableAutocomplete?: boolean;
|
|
13
17
|
fieldName?: string;
|
|
@@ -23,5 +27,5 @@ type StepFieldProps = {
|
|
|
23
27
|
showImageButton?: boolean;
|
|
24
28
|
onFieldFocus?: () => void;
|
|
25
29
|
};
|
|
26
|
-
export declare function StepField({ label,
|
|
30
|
+
export declare function StepField({ label, labelToggle, value, onChange, autoFocus, focusSignal, multiline, enableAutocomplete, fieldName, suggestionFilter, suggestionsOverride, onSuggestionSelect, readOnly, showSuggestionsOnFocus, enableImageUpload, onImageFile, rightAction, showFormattingButtons, showImageButton, onFieldFocus, }: StepFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
27
31
|
export {};
|