@checkstack/ui 0.5.3 → 1.0.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/CHANGELOG.md +33 -0
- package/package.json +3 -10
- package/src/components/CodeEditor/CodeEditor.tsx +14 -420
- package/src/components/CodeEditor/MonacoEditor.tsx +530 -0
- package/src/components/CodeEditor/generateTypeDefinitions.ts +169 -0
- package/src/components/CodeEditor/index.ts +4 -3
- package/src/components/CodeEditor/templateUtils.test.ts +87 -0
- package/src/components/CodeEditor/templateUtils.ts +81 -0
- package/src/components/DynamicForm/FormField.tsx +13 -7
- package/src/components/DynamicForm/MultiTypeEditorField.tsx +33 -0
- package/src/components/DynamicForm/utils.ts +3 -0
- package/src/components/CodeEditor/languageSupport/enterBehavior.test.ts +0 -173
- package/src/components/CodeEditor/languageSupport/enterBehavior.ts +0 -35
- package/src/components/CodeEditor/languageSupport/index.ts +0 -22
- package/src/components/CodeEditor/languageSupport/json-utils.ts +0 -117
- package/src/components/CodeEditor/languageSupport/json.test.ts +0 -274
- package/src/components/CodeEditor/languageSupport/json.ts +0 -139
- package/src/components/CodeEditor/languageSupport/markdown-utils.ts +0 -65
- package/src/components/CodeEditor/languageSupport/markdown.test.ts +0 -245
- package/src/components/CodeEditor/languageSupport/markdown.ts +0 -134
- package/src/components/CodeEditor/languageSupport/types.ts +0 -48
- package/src/components/CodeEditor/languageSupport/xml-utils.ts +0 -94
- package/src/components/CodeEditor/languageSupport/xml.test.ts +0 -239
- package/src/components/CodeEditor/languageSupport/xml.ts +0 -116
- package/src/components/CodeEditor/languageSupport/yaml-utils.ts +0 -101
- package/src/components/CodeEditor/languageSupport/yaml.test.ts +0 -203
- package/src/components/CodeEditor/languageSupport/yaml.ts +0 -120
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @checkstack/ui
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- f676e11: Add script execution support and migrate CodeEditor to Monaco
|
|
8
|
+
|
|
9
|
+
**Integration providers** (`@checkstack/integration-script-backend`):
|
|
10
|
+
|
|
11
|
+
- **Script** - Execute TypeScript/JavaScript with context object
|
|
12
|
+
- **Bash** - Execute shell scripts with environment variables ($EVENT*ID, $PAYLOAD*\*)
|
|
13
|
+
|
|
14
|
+
**Health check collectors** (`@checkstack/healthcheck-script-backend`):
|
|
15
|
+
|
|
16
|
+
- **InlineScriptCollector** - Run TypeScript directly for health checks
|
|
17
|
+
- **ExecuteCollector** - Bash syntax highlighting for command field
|
|
18
|
+
|
|
19
|
+
**CodeEditor migration to Monaco** (`@checkstack/ui`):
|
|
20
|
+
|
|
21
|
+
- Replaced CodeMirror with Monaco Editor (VS Code's editor)
|
|
22
|
+
- Full TypeScript/JavaScript IntelliSense with custom type definitions
|
|
23
|
+
- Added `generateTypeDefinitions()` for JSON Schema → TypeScript conversion
|
|
24
|
+
- Removed all CodeMirror dependencies
|
|
25
|
+
|
|
26
|
+
**Type updates** (`@checkstack/common`):
|
|
27
|
+
|
|
28
|
+
- Added `javascript`, `typescript`, and `bash` to `EditorType` union
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- Updated dependencies [f676e11]
|
|
33
|
+
- @checkstack/common@0.6.2
|
|
34
|
+
- @checkstack/frontend-api@0.3.5
|
|
35
|
+
|
|
3
36
|
## 0.5.3
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@checkstack/common": "0.6.1",
|
|
8
8
|
"@checkstack/frontend-api": "0.3.4",
|
|
9
|
-
"@
|
|
10
|
-
"@codemirror/lang-json": "^6.0.2",
|
|
11
|
-
"@codemirror/lang-markdown": "^6.5.0",
|
|
12
|
-
"@codemirror/lang-xml": "^6.1.0",
|
|
13
|
-
"@codemirror/lang-yaml": "^6.1.2",
|
|
14
|
-
"@codemirror/language": "^6.12.1",
|
|
15
|
-
"@codemirror/state": "^6.5.4",
|
|
16
|
-
"@codemirror/view": "^6.39.11",
|
|
9
|
+
"@monaco-editor/react": "^4.7.0",
|
|
17
10
|
"@radix-ui/react-accordion": "^1.2.12",
|
|
18
11
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
19
12
|
"@radix-ui/react-popover": "^1.1.15",
|
|
20
13
|
"@radix-ui/react-select": "^2.2.6",
|
|
21
14
|
"@radix-ui/react-slot": "^1.2.4",
|
|
22
|
-
"@uiw/react-codemirror": "^4.25.4",
|
|
23
15
|
"ajv": "^8.17.1",
|
|
24
16
|
"ajv-formats": "^3.0.1",
|
|
25
17
|
"class-variance-authority": "^0.7.1",
|
|
26
18
|
"clsx": "^2.1.0",
|
|
27
19
|
"date-fns": "^4.1.0",
|
|
28
20
|
"lucide-react": "0.562.0",
|
|
21
|
+
"monaco-editor": "^0.55.1",
|
|
29
22
|
"react": "^18.2.0",
|
|
30
23
|
"react-day-picker": "^9.13.0",
|
|
31
24
|
"react-markdown": "^10.1.0",
|
|
@@ -1,420 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type CompletionContext,
|
|
16
|
-
type CompletionResult,
|
|
17
|
-
} from "@codemirror/autocomplete";
|
|
18
|
-
import { indentUnit, getIndentUnit, indentString } from "@codemirror/language";
|
|
19
|
-
import {
|
|
20
|
-
jsonLanguageSupport,
|
|
21
|
-
yamlLanguageSupport,
|
|
22
|
-
xmlLanguageSupport,
|
|
23
|
-
markdownLanguageSupport,
|
|
24
|
-
isBetweenBrackets,
|
|
25
|
-
type LanguageSupport,
|
|
26
|
-
} from "./languageSupport";
|
|
27
|
-
|
|
28
|
-
export type CodeEditorLanguage = "json" | "yaml" | "xml" | "markdown";
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A single payload property available for templating
|
|
32
|
-
*/
|
|
33
|
-
export interface TemplateProperty {
|
|
34
|
-
/** Full path to the property, e.g., "payload.incident.title" */
|
|
35
|
-
path: string;
|
|
36
|
-
/** Type of the property, e.g., "string", "number", "boolean" */
|
|
37
|
-
type: string;
|
|
38
|
-
/** Optional description of the property */
|
|
39
|
-
description?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface CodeEditorProps {
|
|
43
|
-
/** Unique identifier for the editor */
|
|
44
|
-
id?: string;
|
|
45
|
-
/** Current value of the editor */
|
|
46
|
-
value: string;
|
|
47
|
-
/** Callback when the value changes */
|
|
48
|
-
onChange: (value: string) => void;
|
|
49
|
-
/** Language for syntax highlighting */
|
|
50
|
-
language?: CodeEditorLanguage;
|
|
51
|
-
/** Minimum height of the editor */
|
|
52
|
-
minHeight?: string;
|
|
53
|
-
/** Whether the editor is read-only */
|
|
54
|
-
readOnly?: boolean;
|
|
55
|
-
/** Placeholder text when empty */
|
|
56
|
-
placeholder?: string;
|
|
57
|
-
/**
|
|
58
|
-
* Optional template properties for autocomplete.
|
|
59
|
-
* When provided, typing "{{" triggers autocomplete with available template variables.
|
|
60
|
-
*/
|
|
61
|
-
templateProperties?: TemplateProperty[];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Language support registry - add new languages here
|
|
65
|
-
const languageRegistry: Record<CodeEditorLanguage, LanguageSupport> = {
|
|
66
|
-
json: jsonLanguageSupport,
|
|
67
|
-
yaml: yamlLanguageSupport,
|
|
68
|
-
xml: xmlLanguageSupport,
|
|
69
|
-
markdown: markdownLanguageSupport,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Get display type with color info for autocomplete
|
|
74
|
-
*/
|
|
75
|
-
function getTypeInfo(type: string): string {
|
|
76
|
-
return type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Create a ViewPlugin for template-aware syntax highlighting.
|
|
81
|
-
* Uses the language's buildDecorations function to generate decorations.
|
|
82
|
-
*/
|
|
83
|
-
function createTemplateHighlighter(languageSupport: LanguageSupport) {
|
|
84
|
-
return ViewPlugin.fromClass(
|
|
85
|
-
class {
|
|
86
|
-
decorations: DecorationSet;
|
|
87
|
-
|
|
88
|
-
constructor(view: EditorView) {
|
|
89
|
-
this.decorations = this.buildDecorations(view);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
buildDecorations(view: EditorView): DecorationSet {
|
|
93
|
-
const builder = new RangeSetBuilder<Decoration>();
|
|
94
|
-
const doc = view.state.doc.toString();
|
|
95
|
-
const ranges = languageSupport.buildDecorations(doc);
|
|
96
|
-
|
|
97
|
-
for (const range of ranges) {
|
|
98
|
-
builder.add(range.from, range.to, range.decoration);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return builder.finish();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
update(update: ViewUpdate) {
|
|
105
|
-
if (update.docChanged || update.viewportChanged) {
|
|
106
|
-
this.decorations = this.buildDecorations(update.view);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
decorations: (v) => v.decorations,
|
|
112
|
-
},
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Create a CodeMirror autocomplete extension for template properties.
|
|
118
|
-
* Triggers when user types "{{" and offers completions from templateProperties.
|
|
119
|
-
*/
|
|
120
|
-
function createTemplateAutocomplete(
|
|
121
|
-
templateProperties: TemplateProperty[],
|
|
122
|
-
languageSupport: LanguageSupport,
|
|
123
|
-
): ReturnType<typeof autocompletion> {
|
|
124
|
-
return autocompletion({
|
|
125
|
-
override: [
|
|
126
|
-
(context: CompletionContext): CompletionResult | null => {
|
|
127
|
-
// Look for {{ pattern before cursor
|
|
128
|
-
const textBefore = context.state.sliceDoc(0, context.pos);
|
|
129
|
-
const recentText = context.state.sliceDoc(
|
|
130
|
-
Math.max(0, context.pos - 50),
|
|
131
|
-
context.pos,
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
// Find the last {{ that doesn't have a matching }}
|
|
135
|
-
const lastOpenBrace = recentText.lastIndexOf("{{");
|
|
136
|
-
const lastCloseBrace = recentText.lastIndexOf("}}");
|
|
137
|
-
|
|
138
|
-
if (lastOpenBrace === -1 || lastOpenBrace < lastCloseBrace) {
|
|
139
|
-
// eslint-disable-next-line unicorn/no-null -- CodeMirror API requires null
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Validate position based on text BEFORE the {{ started
|
|
144
|
-
// We exclude the {{ from validation because it confuses most parsers
|
|
145
|
-
const positionOfTemplateStart =
|
|
146
|
-
context.pos - recentText.length + lastOpenBrace;
|
|
147
|
-
const textBeforeTemplate = textBefore.slice(0, positionOfTemplateStart);
|
|
148
|
-
if (!languageSupport.isValidTemplatePosition(textBeforeTemplate)) {
|
|
149
|
-
// eslint-disable-next-line unicorn/no-null -- CodeMirror API requires null
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Calculate the position in the document where {{ starts
|
|
154
|
-
const startOffset = context.pos - recentText.length + lastOpenBrace;
|
|
155
|
-
const query = recentText.slice(lastOpenBrace + 2).toLowerCase();
|
|
156
|
-
|
|
157
|
-
// Check for auto-closed braces after cursor position
|
|
158
|
-
// When user types {{ with bracket auto-close, it becomes {{}}
|
|
159
|
-
// We need to consume any trailing }} when completing
|
|
160
|
-
const textAfter = context.state.sliceDoc(context.pos, context.pos + 4);
|
|
161
|
-
let endOffset = context.pos;
|
|
162
|
-
if (textAfter.startsWith("}}")) {
|
|
163
|
-
endOffset += 2;
|
|
164
|
-
} else if (textAfter.startsWith("}")) {
|
|
165
|
-
// Just one } from first auto-close
|
|
166
|
-
endOffset += 1;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Filter properties based on query
|
|
170
|
-
const filtered = templateProperties.filter((prop) =>
|
|
171
|
-
prop.path.toLowerCase().includes(query),
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
if (filtered.length === 0 && query.length > 0) {
|
|
175
|
-
// eslint-disable-next-line unicorn/no-null -- CodeMirror API requires null
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
from: startOffset,
|
|
181
|
-
to: endOffset,
|
|
182
|
-
options: filtered.map((prop) => ({
|
|
183
|
-
label: `{{${prop.path}}}`,
|
|
184
|
-
displayLabel: prop.path,
|
|
185
|
-
type: "variable",
|
|
186
|
-
detail: getTypeInfo(prop.type),
|
|
187
|
-
info: prop.description,
|
|
188
|
-
boost: prop.path.toLowerCase().startsWith(query) ? 1 : 0,
|
|
189
|
-
})),
|
|
190
|
-
validFor: /^\{\{[\w.]*$/,
|
|
191
|
-
};
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
activateOnTyping: true,
|
|
195
|
-
icons: false,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* A code editor component with syntax highlighting and optional template autocomplete.
|
|
201
|
-
* Wraps @uiw/react-codemirror for consistent styling and API across the platform.
|
|
202
|
-
*/
|
|
203
|
-
export const CodeEditor: React.FC<CodeEditorProps> = ({
|
|
204
|
-
id,
|
|
205
|
-
value,
|
|
206
|
-
onChange,
|
|
207
|
-
language = "json",
|
|
208
|
-
minHeight = "100px",
|
|
209
|
-
readOnly = false,
|
|
210
|
-
placeholder,
|
|
211
|
-
templateProperties,
|
|
212
|
-
}) => {
|
|
213
|
-
const extensions = React.useMemo(() => {
|
|
214
|
-
const languageSupport = languageRegistry[language];
|
|
215
|
-
const hasTemplates = templateProperties && templateProperties.length > 0;
|
|
216
|
-
|
|
217
|
-
const exts = [
|
|
218
|
-
EditorView.lineWrapping,
|
|
219
|
-
EditorView.theme({
|
|
220
|
-
"&": {
|
|
221
|
-
fontSize: "14px",
|
|
222
|
-
fontFamily: "ui-monospace, monospace",
|
|
223
|
-
backgroundColor: "transparent",
|
|
224
|
-
},
|
|
225
|
-
".cm-scroller": {
|
|
226
|
-
backgroundColor: "transparent",
|
|
227
|
-
overflow: "auto",
|
|
228
|
-
},
|
|
229
|
-
// minHeight must be on .cm-content and .cm-gutter, not the wrapper (per CM docs)
|
|
230
|
-
".cm-content, .cm-gutter": {
|
|
231
|
-
minHeight: minHeight,
|
|
232
|
-
},
|
|
233
|
-
".cm-content": {
|
|
234
|
-
padding: "10px",
|
|
235
|
-
},
|
|
236
|
-
// Cursor/caret styling
|
|
237
|
-
".cm-cursor, .cm-dropCursor": {
|
|
238
|
-
borderLeftColor: "hsl(var(--foreground))",
|
|
239
|
-
borderLeftWidth: "2px",
|
|
240
|
-
},
|
|
241
|
-
".cm-line": {
|
|
242
|
-
color: "hsl(var(--foreground))",
|
|
243
|
-
},
|
|
244
|
-
".cm-gutters": {
|
|
245
|
-
backgroundColor: "transparent",
|
|
246
|
-
color: "hsl(var(--muted-foreground))",
|
|
247
|
-
border: "none",
|
|
248
|
-
},
|
|
249
|
-
"&.cm-focused": {
|
|
250
|
-
outline: "none",
|
|
251
|
-
},
|
|
252
|
-
// JSON syntax highlighting for dark/light mode
|
|
253
|
-
".cm-string": {
|
|
254
|
-
color: "hsl(142.1, 76.2%, 36.3%)",
|
|
255
|
-
},
|
|
256
|
-
".cm-number": {
|
|
257
|
-
color: "hsl(217.2, 91.2%, 59.8%)",
|
|
258
|
-
},
|
|
259
|
-
".cm-propertyName": {
|
|
260
|
-
color: "hsl(280, 65%, 60%)",
|
|
261
|
-
},
|
|
262
|
-
".cm-keyword": {
|
|
263
|
-
color: "hsl(280, 65%, 60%)",
|
|
264
|
-
},
|
|
265
|
-
".cm-punctuation": {
|
|
266
|
-
color: "hsl(var(--muted-foreground))",
|
|
267
|
-
},
|
|
268
|
-
// Placeholder styling
|
|
269
|
-
".cm-placeholder": {
|
|
270
|
-
color: "hsl(var(--muted-foreground))",
|
|
271
|
-
},
|
|
272
|
-
// JSON syntax highlighting via decorations (overrides Lezer parser)
|
|
273
|
-
".cm-json-property": {
|
|
274
|
-
color: "hsl(280, 65%, 60%)",
|
|
275
|
-
},
|
|
276
|
-
".cm-json-string": {
|
|
277
|
-
color: "hsl(142.1, 76.2%, 36.3%)",
|
|
278
|
-
},
|
|
279
|
-
".cm-json-number": {
|
|
280
|
-
color: "hsl(217.2, 91.2%, 59.8%)",
|
|
281
|
-
},
|
|
282
|
-
".cm-json-keyword": {
|
|
283
|
-
color: "hsl(280, 65%, 60%)",
|
|
284
|
-
},
|
|
285
|
-
// Template expression highlighting
|
|
286
|
-
".cm-template-expression": {
|
|
287
|
-
color: "hsl(190, 70%, 50%)",
|
|
288
|
-
fontWeight: "500",
|
|
289
|
-
},
|
|
290
|
-
// Style for autocomplete popup
|
|
291
|
-
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
292
|
-
backgroundColor: "hsl(var(--popover))",
|
|
293
|
-
border: "1px solid hsl(var(--border))",
|
|
294
|
-
borderRadius: "0.375rem",
|
|
295
|
-
boxShadow:
|
|
296
|
-
"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
|
|
297
|
-
},
|
|
298
|
-
".cm-tooltip-autocomplete ul": {
|
|
299
|
-
fontFamily: "ui-monospace, monospace",
|
|
300
|
-
fontSize: "0.75rem",
|
|
301
|
-
},
|
|
302
|
-
".cm-tooltip-autocomplete ul li": {
|
|
303
|
-
padding: "0.25rem 0.5rem",
|
|
304
|
-
},
|
|
305
|
-
".cm-tooltip-autocomplete ul li[aria-selected]": {
|
|
306
|
-
backgroundColor: "hsl(var(--accent))",
|
|
307
|
-
color: "hsl(var(--accent-foreground))",
|
|
308
|
-
},
|
|
309
|
-
".cm-completionLabel": {
|
|
310
|
-
fontFamily: "ui-monospace, monospace",
|
|
311
|
-
},
|
|
312
|
-
".cm-completionDetail": {
|
|
313
|
-
marginLeft: "0.5rem",
|
|
314
|
-
fontStyle: "normal",
|
|
315
|
-
color: "hsl(var(--muted-foreground))",
|
|
316
|
-
},
|
|
317
|
-
}),
|
|
318
|
-
];
|
|
319
|
-
|
|
320
|
-
// Always add language extension for features (indentation, bracket matching, etc.)
|
|
321
|
-
if (languageSupport) {
|
|
322
|
-
exts.push(languageSupport.extension);
|
|
323
|
-
|
|
324
|
-
// Create custom Enter key handler that applies our indentation
|
|
325
|
-
// This is needed because the language parsers may get confused by templates
|
|
326
|
-
// or may not provide the indentation we want
|
|
327
|
-
const customEnterKeymap = keymap.of([
|
|
328
|
-
{
|
|
329
|
-
key: "Enter",
|
|
330
|
-
run: (view) => {
|
|
331
|
-
const state = view.state;
|
|
332
|
-
|
|
333
|
-
// If autocomplete is active, let it handle Enter for selection
|
|
334
|
-
if (completionStatus(state) === "active") {
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const pos = state.selection.main.head;
|
|
339
|
-
const textBefore = state.sliceDoc(0, pos);
|
|
340
|
-
const textAfter = state.sliceDoc(pos);
|
|
341
|
-
const unit = getIndentUnit(state);
|
|
342
|
-
const indent = languageSupport.calculateIndentation(
|
|
343
|
-
textBefore + "\n",
|
|
344
|
-
unit,
|
|
345
|
-
);
|
|
346
|
-
const indentStr = indentString(state, indent);
|
|
347
|
-
|
|
348
|
-
// Check if we're between matching brackets/tags
|
|
349
|
-
// This handles cases like: {|}, [|], <tag>|</tag>
|
|
350
|
-
if (isBetweenBrackets(textBefore, textAfter)) {
|
|
351
|
-
// Split: add newline with indent, then newline with previous indent for closing
|
|
352
|
-
const prevIndent = Math.max(0, indent - unit);
|
|
353
|
-
const prevIndentStr = indentString(state, prevIndent);
|
|
354
|
-
|
|
355
|
-
view.dispatch({
|
|
356
|
-
changes: {
|
|
357
|
-
from: pos,
|
|
358
|
-
to: pos,
|
|
359
|
-
insert: "\n" + indentStr + "\n" + prevIndentStr,
|
|
360
|
-
},
|
|
361
|
-
selection: { anchor: pos + 1 + indentStr.length },
|
|
362
|
-
scrollIntoView: true,
|
|
363
|
-
userEvent: "input",
|
|
364
|
-
});
|
|
365
|
-
} else {
|
|
366
|
-
// Normal: insert newline with calculated indentation
|
|
367
|
-
view.dispatch({
|
|
368
|
-
changes: { from: pos, to: pos, insert: "\n" + indentStr },
|
|
369
|
-
selection: { anchor: pos + 1 + indentStr.length },
|
|
370
|
-
scrollIntoView: true,
|
|
371
|
-
userEvent: "input",
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
return true;
|
|
375
|
-
},
|
|
376
|
-
},
|
|
377
|
-
]);
|
|
378
|
-
|
|
379
|
-
// Always add indentation support and custom highlighter for consistent behavior
|
|
380
|
-
// Prec.highest ensures our colors take precedence over language parser output
|
|
381
|
-
exts.push(
|
|
382
|
-
indentUnit.of(" "), // Configure 2-space indentation
|
|
383
|
-
Prec.highest(customEnterKeymap), // Override default Enter behavior
|
|
384
|
-
Prec.highest(createTemplateHighlighter(languageSupport)), // Consistent syntax colors
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
// Add template autocomplete if properties provided
|
|
388
|
-
if (hasTemplates) {
|
|
389
|
-
exts.push(
|
|
390
|
-
createTemplateAutocomplete(templateProperties, languageSupport),
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return exts;
|
|
396
|
-
}, [language, templateProperties, minHeight]);
|
|
397
|
-
|
|
398
|
-
return (
|
|
399
|
-
<div
|
|
400
|
-
id={id}
|
|
401
|
-
className="w-full rounded-md border border-input bg-background font-mono text-sm focus-within:ring-2 focus-within:ring-ring focus-within:border-transparent transition-all box-border"
|
|
402
|
-
>
|
|
403
|
-
<CodeMirror
|
|
404
|
-
value={value}
|
|
405
|
-
onChange={onChange}
|
|
406
|
-
extensions={extensions}
|
|
407
|
-
editable={!readOnly}
|
|
408
|
-
placeholder={placeholder}
|
|
409
|
-
basicSetup={{
|
|
410
|
-
lineNumbers: true,
|
|
411
|
-
foldGutter: false,
|
|
412
|
-
highlightActiveLine: false,
|
|
413
|
-
highlightSelectionMatches: false,
|
|
414
|
-
autocompletion: false, // We use our own
|
|
415
|
-
}}
|
|
416
|
-
theme="none"
|
|
417
|
-
/>
|
|
418
|
-
</div>
|
|
419
|
-
);
|
|
420
|
-
};
|
|
1
|
+
// Monaco-based CodeEditor
|
|
2
|
+
// Re-export all from MonacoEditor as the new CodeEditor implementation
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
CodeEditor,
|
|
6
|
+
type CodeEditorProps,
|
|
7
|
+
type CodeEditorLanguage,
|
|
8
|
+
type TemplateProperty,
|
|
9
|
+
} from "./MonacoEditor";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
generateTypeDefinitions,
|
|
13
|
+
type GenerateTypesOptions,
|
|
14
|
+
} from "./generateTypeDefinitions";
|