@mongodb-js/compass-editor 0.29.2 → 0.31.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/dist/actions.js +2 -0
- package/dist/actions.js.map +1 -1
- package/dist/codemirror/ace-compat-autocompleter.d.ts +12 -0
- package/dist/codemirror/ace-compat-autocompleter.d.ts.map +1 -1
- package/dist/codemirror/ace-compat-autocompleter.js +18 -0
- package/dist/codemirror/ace-compat-autocompleter.js.map +1 -1
- package/dist/codemirror/aggregation-autocompleter.js +2 -0
- package/dist/codemirror/aggregation-autocompleter.js.map +1 -1
- package/dist/codemirror/document-autocompleter.d.ts +4 -0
- package/dist/codemirror/document-autocompleter.d.ts.map +1 -1
- package/dist/codemirror/document-autocompleter.js +16 -2
- package/dist/codemirror/document-autocompleter.js.map +1 -1
- package/dist/codemirror/query-autocompleter-with-history.d.ts +7 -1
- package/dist/codemirror/query-autocompleter-with-history.d.ts.map +1 -1
- package/dist/codemirror/query-autocompleter-with-history.js +8 -2
- package/dist/codemirror/query-autocompleter-with-history.js.map +1 -1
- package/dist/codemirror/query-autocompleter.d.ts +4 -0
- package/dist/codemirror/query-autocompleter.d.ts.map +1 -1
- package/dist/codemirror/query-autocompleter.js +4 -0
- package/dist/codemirror/query-autocompleter.js.map +1 -1
- package/dist/codemirror/query-history-autocompleter.d.ts +8 -2
- package/dist/codemirror/query-history-autocompleter.d.ts.map +1 -1
- package/dist/codemirror/query-history-autocompleter.js +91 -13
- package/dist/codemirror/query-history-autocompleter.js.map +1 -1
- package/dist/codemirror/stage-autocompleter.js +1 -0
- package/dist/codemirror/stage-autocompleter.js.map +1 -1
- package/dist/codemirror/utils.d.ts +5 -0
- package/dist/codemirror/utils.d.ts.map +1 -1
- package/dist/codemirror/utils.js +16 -0
- package/dist/codemirror/utils.js.map +1 -1
- package/dist/codemirror/validation-autocompleter.js +15 -0
- package/dist/codemirror/validation-autocompleter.js.map +1 -1
- package/dist/editor.d.ts +19 -2
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +144 -3
- package/dist/editor.js.map +1 -1
- package/dist/prettify.js +5 -1
- package/dist/prettify.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -18,21 +18,29 @@ const rootJsonSchemaCompletion = (from, to) => ({
|
|
|
18
18
|
],
|
|
19
19
|
});
|
|
20
20
|
const isCompletingRequired = (ancestors) => {
|
|
21
|
+
// Required is always an array.
|
|
21
22
|
return ancestors[ancestors.length - 2] === 'required';
|
|
22
23
|
};
|
|
23
24
|
const isCompletingProperties = (ancestors) => {
|
|
24
25
|
return ancestors[ancestors.length - 1] === 'properties';
|
|
25
26
|
};
|
|
26
27
|
const isCompletingBsonType = (ancestors) => {
|
|
28
|
+
// bsonType can either be a string or an array.
|
|
27
29
|
const immediateParent = ancestors[ancestors.length - 1] ?? '';
|
|
28
30
|
return (immediateParent === 'bsonType' ||
|
|
29
31
|
ancestors[ancestors.length - 2] === 'bsonType');
|
|
30
32
|
};
|
|
31
33
|
const isCompletingQueryOperator = (ancestors, operators) => {
|
|
34
|
+
// The query operators also has a $jsonSchema, so we need to filter
|
|
35
|
+
// that out as the context in that case is jsonSchema and not query.
|
|
32
36
|
return ancestors
|
|
33
37
|
.filter((x) => x !== '$jsonSchema')
|
|
34
38
|
.some((x) => operators.includes(x));
|
|
35
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* The $jsonSchema's *required* and *properties* fields are nested,
|
|
42
|
+
* so we need to get the ancestor to get the correct field name.
|
|
43
|
+
*/
|
|
36
44
|
const getNestingAncestor = (ancestors) => {
|
|
37
45
|
return (ancestors
|
|
38
46
|
.filter((x) => !['$jsonSchema'].includes(x))
|
|
@@ -42,8 +50,13 @@ const getNestingAncestor = (ancestors) => {
|
|
|
42
50
|
}
|
|
43
51
|
})
|
|
44
52
|
.filter(Boolean)
|
|
53
|
+
// because field names are represented in dot notation
|
|
45
54
|
.join('.'));
|
|
46
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* As the $jsonSchema's *required* and *properties* fields are nested,
|
|
58
|
+
* we need to filter the fields based on the nesting level (ancestor).
|
|
59
|
+
*/
|
|
47
60
|
const filterFieldsByAncestor = (fields, ancestor) => {
|
|
48
61
|
if (ancestor === '') {
|
|
49
62
|
return fields;
|
|
@@ -82,6 +95,7 @@ const createValidationAutocompleter = (options = {}) => {
|
|
|
82
95
|
const token = (0, utils_1.resolveTokenAtCursor)(context);
|
|
83
96
|
const document = context.state.sliceDoc(0);
|
|
84
97
|
const prefix = context.matchBefore(ace_compat_autocompleter_1.ID_REGEX);
|
|
98
|
+
// At the root level
|
|
85
99
|
if (token.type.isTop) {
|
|
86
100
|
return rootJsonSchemaCompletion(0, document.length);
|
|
87
101
|
}
|
|
@@ -89,6 +103,7 @@ const createValidationAutocompleter = (options = {}) => {
|
|
|
89
103
|
return null;
|
|
90
104
|
}
|
|
91
105
|
const ancestors = (0, utils_1.getAncestryOfToken)(token, document);
|
|
106
|
+
// At the root object {} level.
|
|
92
107
|
if (ancestors.length === 0) {
|
|
93
108
|
return (0, ace_compat_autocompleter_1.createCompletionResultForIdPrefix)({
|
|
94
109
|
prefix,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-autocompleter.js","sourceRoot":"","sources":["../../src/codemirror/validation-autocompleter.ts"],"names":[],"mappings":";;;AACA,2DAA6D;AAC7D,oDAA6C;AAG7C,mCAAmE;AACnE,yEAGoC;AACpC,+DAAiE;AAEjE,MAAM,wBAAwB,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,EAAE,CAAC,CAAC;IAC9D,MAAM,EAAE,KAAK;IACb,IAAI;IACJ,EAAE;IACF,OAAO,EAAE;QACP,IAAA,gCAAiB,EAAC,sCAAsC,EAAE;YACxD,KAAK,EAAE,aAAa;YACpB,IAAI,EAAE,+BAA+B;SACtC,CAAC;KACH;CACF,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,CAAC,SAAmB,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"validation-autocompleter.js","sourceRoot":"","sources":["../../src/codemirror/validation-autocompleter.ts"],"names":[],"mappings":"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"}
|
package/dist/editor.d.ts
CHANGED
|
@@ -103,6 +103,7 @@ export type EditorRef = {
|
|
|
103
103
|
prettify: () => boolean;
|
|
104
104
|
applySnippet: (template: string) => boolean;
|
|
105
105
|
focus: () => boolean;
|
|
106
|
+
cursorDocEnd: () => boolean;
|
|
106
107
|
startCompletion: () => boolean;
|
|
107
108
|
readonly editorContents: string | null;
|
|
108
109
|
readonly editor: EditorView | null;
|
|
@@ -130,8 +131,24 @@ type MultilineEditorProps = EditorProps & {
|
|
|
130
131
|
actionsClassName?: string;
|
|
131
132
|
};
|
|
132
133
|
declare const MultilineEditor: React.ForwardRefExoticComponent<MultilineEditorProps & React.RefAttributes<EditorRef>>;
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Sets the editor value, use this with RTL like this:
|
|
136
|
+
*
|
|
137
|
+
* ```
|
|
138
|
+
* render(<Editor data-testid='my-editor' />);
|
|
139
|
+
* setCodemirrorEditorValue(screen.getByTestId('editor-test-id'), 'my text');
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
declare function setCodemirrorEditorValue(element: Element | string | null, text: string): Promise<void>;
|
|
143
|
+
/**
|
|
144
|
+
* Retrieves the contents of an editor, use this with RTL like this:
|
|
145
|
+
*
|
|
146
|
+
* ```
|
|
147
|
+
* render(<Editor data-testid='my-editor' />);
|
|
148
|
+
* getCodemirrorEditorValue(screen.getByTestId('editor-test-id'));
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
declare function getCodemirrorEditorValue(element: Element | string | null): string;
|
|
135
152
|
export { BaseEditor };
|
|
136
153
|
export { InlineEditor as CodemirrorInlineEditor };
|
|
137
154
|
export { MultilineEditor as CodemirrorMultilineEditor };
|
package/dist/editor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAQN,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAEL,WAAW,IAAI,qBAAqB,EAMpC,UAAU,EACX,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"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"}
|
package/dist/editor.js
CHANGED
|
@@ -62,6 +62,11 @@ const hiddenScrollStyle = (0, compass_components_1.css)({
|
|
|
62
62
|
function isReadOnly(state) {
|
|
63
63
|
return state.facet(state_1.EditorState.readOnly);
|
|
64
64
|
}
|
|
65
|
+
// Breaks keyboard navigation out of the editor, but we want that.
|
|
66
|
+
// A user has to hit `Escape` then `Tab` to enter keyboard navigation.
|
|
67
|
+
// Note that the ordering of these matters as no more key handlers are called
|
|
68
|
+
// after the first corresponding `run` function returns true.
|
|
69
|
+
// https://codemirror.net/examples/tab/
|
|
65
70
|
const tabKeymap = [
|
|
66
71
|
{
|
|
67
72
|
key: 'Tab',
|
|
@@ -78,6 +83,9 @@ const tabKeymap = [
|
|
|
78
83
|
if (isReadOnly(state)) {
|
|
79
84
|
return false;
|
|
80
85
|
}
|
|
86
|
+
// `indentWithTab` will indent when `Tab` is pressed without any selection (like
|
|
87
|
+
// in browser devtools for example). Instead we want to input the tab symbol in
|
|
88
|
+
// that case, to have behavior similar to VSCode's editors.
|
|
81
89
|
if (!state.selection.ranges.some((range) => !range.empty)) {
|
|
82
90
|
dispatch(state.update(state.replaceSelection('\t'), {
|
|
83
91
|
scrollIntoView: true,
|
|
@@ -101,6 +109,7 @@ exports.editorPalette = {
|
|
|
101
109
|
gutterActiveLineBackgroundColor: (0, polished_1.rgba)(compass_components_1.palette.gray.light2, 0.5),
|
|
102
110
|
gutterFoldButtonColor: compass_components_1.palette.black,
|
|
103
111
|
cursorColor: compass_components_1.palette.gray.base,
|
|
112
|
+
// Semi-transparent opacity so that the selection background can still be seen.
|
|
104
113
|
activeLineBackgroundColor: (0, polished_1.rgba)(compass_components_1.palette.gray.light2, 0.5),
|
|
105
114
|
selectionBackgroundColor: compass_components_1.palette.blue.light2,
|
|
106
115
|
bracketBorderColor: compass_components_1.palette.gray.light1,
|
|
@@ -125,6 +134,7 @@ exports.editorPalette = {
|
|
|
125
134
|
gutterActiveLineBackgroundColor: (0, polished_1.rgba)(compass_components_1.palette.gray.dark2, 0.5),
|
|
126
135
|
gutterFoldButtonColor: compass_components_1.palette.white,
|
|
127
136
|
cursorColor: compass_components_1.palette.green.base,
|
|
137
|
+
// Semi-transparent opacity so that the selection background can still be seen.
|
|
128
138
|
activeLineBackgroundColor: (0, polished_1.rgba)(compass_components_1.palette.gray.dark2, 0.5),
|
|
129
139
|
selectionBackgroundColor: compass_components_1.palette.gray.dark2,
|
|
130
140
|
bracketBorderColor: compass_components_1.palette.gray.light1,
|
|
@@ -362,7 +372,7 @@ function getStylesForTheme(theme) {
|
|
|
362
372
|
marginTop: 0,
|
|
363
373
|
paddingTop: 0,
|
|
364
374
|
fontSize: '12px',
|
|
365
|
-
maxHeight:
|
|
375
|
+
maxHeight: `${compass_components_1.spacing[1600] * 5}px`,
|
|
366
376
|
},
|
|
367
377
|
'& .cm-tooltip .completion-info p': {
|
|
368
378
|
margin: 0,
|
|
@@ -377,6 +387,9 @@ function getStylesForTheme(theme) {
|
|
|
377
387
|
marginBottom: 0,
|
|
378
388
|
},
|
|
379
389
|
'& .cm-widgetBuffer': {
|
|
390
|
+
// Default is text-top which causes weird 1px added to the line height
|
|
391
|
+
// when widget (in our case this is placeholder widget) is shown in the
|
|
392
|
+
// editor
|
|
380
393
|
verticalAlign: 'top',
|
|
381
394
|
},
|
|
382
395
|
}, { dark: theme === 'dark' });
|
|
@@ -386,6 +399,9 @@ const themeStyles = {
|
|
|
386
399
|
dark: getStylesForTheme('dark'),
|
|
387
400
|
};
|
|
388
401
|
function getHighlightStyleForTheme(theme) {
|
|
402
|
+
// For the full list of tags parsed by lezer for javascript / json see:
|
|
403
|
+
// https://github.com/lezer-parser/javascript/blob/main/src/highlight.js
|
|
404
|
+
// https://github.com/lezer-parser/json/blob/main/src/highlight.js
|
|
389
405
|
return language_2.HighlightStyle.define([
|
|
390
406
|
{
|
|
391
407
|
tag: [
|
|
@@ -462,6 +478,7 @@ function createFoldGutterExtension() {
|
|
|
462
478
|
});
|
|
463
479
|
}
|
|
464
480
|
const javascriptExpression = lang_javascript_1.javascriptLanguage.configure({
|
|
481
|
+
// We always use editor to edit single expressions in Compass
|
|
465
482
|
top: 'SingleExpression',
|
|
466
483
|
});
|
|
467
484
|
exports.languages = {
|
|
@@ -486,12 +503,29 @@ async function waitUntilEditorIsReady(editorView, signal) {
|
|
|
486
503
|
}
|
|
487
504
|
return true;
|
|
488
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Codemirror editor throws when the state update is being applied while another
|
|
508
|
+
* one is in progress and doesn't give us a way to schedule updates otherwise.
|
|
509
|
+
* They do have some good reasoning[0] for it, but as we are using this library
|
|
510
|
+
* in React context where having multiple effects instead of grouping them all
|
|
511
|
+
* in one place is preferable over grouping them all together, we have this
|
|
512
|
+
* method to allow to schedule updates and apply them when editor gets idle
|
|
513
|
+
*
|
|
514
|
+
* [0]: https://discuss.codemirror.net/t/should-dispatched-transactions-be-added-to-a-queue/4610/4
|
|
515
|
+
*/
|
|
489
516
|
async function scheduleDispatch(editorView, transactions, signal) {
|
|
490
517
|
await waitUntilEditorIsReady(editorView, signal);
|
|
491
518
|
transactions = Array.isArray(transactions) ? transactions : [transactions];
|
|
492
519
|
editorView.dispatch(...transactions);
|
|
493
520
|
return true;
|
|
494
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* https://codemirror.net/examples/config/#dynamic-configuration
|
|
524
|
+
* @param fn
|
|
525
|
+
* @param editorViewRef
|
|
526
|
+
* @param value
|
|
527
|
+
* @returns
|
|
528
|
+
*/
|
|
495
529
|
function useCodemirrorExtensionCompartment(fn, value, editorViewRef) {
|
|
496
530
|
const extensionCreatorRef = (0, react_1.useRef)(fn);
|
|
497
531
|
extensionCreatorRef.current = fn;
|
|
@@ -514,9 +548,13 @@ function useCodemirrorExtensionCompartment(fn, value, editorViewRef) {
|
|
|
514
548
|
return initialExtensionRef.current;
|
|
515
549
|
}
|
|
516
550
|
const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText: _initialText, text, onChangeText, language = 'json', showLineNumbers = true, showFoldGutter = true, showAnnotationsGutter = true, showScroll = true, highlightActiveLine: shouldHighlightActiveLine = true, annotations, completer, darkMode: _darkMode, disabled = false, className, readOnly = false, onLoad = () => {
|
|
551
|
+
/**/
|
|
517
552
|
}, onFocus = () => {
|
|
553
|
+
/**/
|
|
518
554
|
}, onBlur = () => {
|
|
555
|
+
/**/
|
|
519
556
|
}, onPaste = () => {
|
|
557
|
+
/**/
|
|
520
558
|
}, minLines, maxLines, lineHeight = 16, placeholder, commands, initialJSONFoldAll: _initialJSONFoldAll = true, ...props }, ref) {
|
|
521
559
|
const darkMode = (0, compass_components_1.useDarkMode)(_darkMode);
|
|
522
560
|
const onChangeTextRef = (0, react_1.useRef)(onChangeText);
|
|
@@ -535,6 +573,7 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
535
573
|
hasScroll: false,
|
|
536
574
|
});
|
|
537
575
|
const initialJSONFoldAll = (0, react_1.useRef)(_initialJSONFoldAll);
|
|
576
|
+
// Always keep the latest reference of the callbacks
|
|
538
577
|
onChangeTextRef.current = onChangeText;
|
|
539
578
|
onLoadRef.current = onLoad;
|
|
540
579
|
onFocusRef.current = onFocus;
|
|
@@ -579,6 +618,12 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
579
618
|
editorViewRef.current.focus();
|
|
580
619
|
return true;
|
|
581
620
|
},
|
|
621
|
+
cursorDocEnd() {
|
|
622
|
+
if (!editorViewRef.current) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
return (0, commands_1.cursorDocEnd)(editorViewRef.current);
|
|
626
|
+
},
|
|
582
627
|
startCompletion() {
|
|
583
628
|
if (!editorViewRef.current) {
|
|
584
629
|
return false;
|
|
@@ -614,6 +659,7 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
614
659
|
return themeStyles[darkMode ? 'dark' : 'light'];
|
|
615
660
|
}, darkMode, editorViewRef);
|
|
616
661
|
const lineHeightExtension = useCodemirrorExtensionCompartment(() => {
|
|
662
|
+
// See https://codemirror.net/examples/styling/#overflow-and-scrolling
|
|
617
663
|
return view_1.EditorView.theme({
|
|
618
664
|
'& .cm-scroller': {
|
|
619
665
|
lineHeight: `${lineHeight}px`,
|
|
@@ -635,6 +681,9 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
635
681
|
const foldGutterExtension = useCodemirrorExtensionCompartment(() => {
|
|
636
682
|
return showFoldGutter ? createFoldGutterExtension() : [];
|
|
637
683
|
}, showFoldGutter, editorViewRef);
|
|
684
|
+
// By default we want to show annotations gutter so that the gutters don't
|
|
685
|
+
// jump when annotations are added / removed. This can be opted out by setting
|
|
686
|
+
// showAnnotationsGutter to false
|
|
638
687
|
const shouldShowAnnotationsGutter = showAnnotationsGutter || (annotations && annotations.length === 0);
|
|
639
688
|
const annotationsGutterExtension = useCodemirrorExtensionCompartment(() => {
|
|
640
689
|
return shouldShowAnnotationsGutter ? (0, lint_1.lintGutter)() : [];
|
|
@@ -679,6 +728,10 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
679
728
|
const domNode = editorContainerRef.current;
|
|
680
729
|
const editor = (editorViewRef.current = new view_1.EditorView({
|
|
681
730
|
doc: initialText.current,
|
|
731
|
+
// Cherry-picked from codemirror basicSetup extensions to match the ones
|
|
732
|
+
// we had with ace-editor. There are many more that we might want to add,
|
|
733
|
+
// but this is good as a starting point
|
|
734
|
+
// https://github.com/codemirror/basic-setup/blob/5b4dafdb3b02271bd3fd507d86982208457d8c5b/src/codemirror.ts#L12-L49
|
|
682
735
|
extensions: [
|
|
683
736
|
state_1.EditorState.tabSize.of(2),
|
|
684
737
|
annotationsGutterExtension,
|
|
@@ -697,7 +750,11 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
697
750
|
lineHeightExtension,
|
|
698
751
|
themeConfigExtension,
|
|
699
752
|
placeholderExtension,
|
|
753
|
+
// User provided commands should take precedence over default keybindings.
|
|
700
754
|
commandsExtension,
|
|
755
|
+
// The order of this keymap matters, when the `run` function of the corresponding key
|
|
756
|
+
// returns false it goes to the next corresponding key, if it returns true then
|
|
757
|
+
// it completes and does not try further handlers.
|
|
701
758
|
view_1.keymap.of([
|
|
702
759
|
{
|
|
703
760
|
key: 'Ctrl-Shift-b',
|
|
@@ -707,6 +764,8 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
707
764
|
key: 'Ctrl-Shift-c',
|
|
708
765
|
run: copyAll,
|
|
709
766
|
},
|
|
767
|
+
// Close brackets keymap overrides default backspace handler for
|
|
768
|
+
// matching bracket case
|
|
710
769
|
...autocomplete_1.closeBracketsKeymap,
|
|
711
770
|
...commands_1.defaultKeymap,
|
|
712
771
|
...commands_1.historyKeymap,
|
|
@@ -714,6 +773,9 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
714
773
|
...autocomplete_1.completionKeymap,
|
|
715
774
|
...tabKeymap,
|
|
716
775
|
]),
|
|
776
|
+
// Supply the document body as the tooltip parent
|
|
777
|
+
// because we are using containment contexts for container
|
|
778
|
+
// queries which offset things otherwise.
|
|
717
779
|
(0, view_1.tooltips)({
|
|
718
780
|
parent: document.body,
|
|
719
781
|
}),
|
|
@@ -726,6 +788,12 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
726
788
|
onChangeTextRef.current?.(editorText, update);
|
|
727
789
|
}
|
|
728
790
|
}),
|
|
791
|
+
/**
|
|
792
|
+
* EditorView.domEventHandlers use real DOM events. However,
|
|
793
|
+
* we want to bubble these events up to our React components
|
|
794
|
+
* properly. We will be casting them to React synthetic events,
|
|
795
|
+
* as for our use case, they should behave identical.
|
|
796
|
+
*/
|
|
729
797
|
view_1.EditorView.domEventHandlers({
|
|
730
798
|
focus(event) {
|
|
731
799
|
onFocusRef.current?.(event);
|
|
@@ -740,9 +808,21 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
740
808
|
],
|
|
741
809
|
parent: domNode,
|
|
742
810
|
}));
|
|
811
|
+
// For debugging / e2e tests purposes
|
|
743
812
|
domNode._cm = editor;
|
|
744
813
|
onLoadRef.current(editor);
|
|
745
814
|
if (editor && initialLanguage.current === 'json') {
|
|
815
|
+
// By default codemirror uses partial parser that will parse only visible
|
|
816
|
+
// part of the code on the screen. This is extremely performant, but
|
|
817
|
+
// collides with our folding logic for the json view. For json we collapse
|
|
818
|
+
// everything but the very top level document. To be able to do that we
|
|
819
|
+
// need to ensure that the whole syntax tree is available to the fold
|
|
820
|
+
// extension.
|
|
821
|
+
//
|
|
822
|
+
// WARNING: This is a massive performance bottleneck in editor rendering,
|
|
823
|
+
// we do parsing with a timeout to avoid locking main thread for too long,
|
|
824
|
+
// but even this is a compromise. If this becomes an issue, we might
|
|
825
|
+
// consider disabling this folding by default.
|
|
746
826
|
const docLength = editor.state.doc.length;
|
|
747
827
|
const isSyntaxTreeAvailable = (0, language_1.syntaxTreeAvailable)(editor.state, docLength) ||
|
|
748
828
|
(0, language_1.forceParsing)(editor, docLength, 150);
|
|
@@ -750,6 +830,7 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
750
830
|
foldAll(editor);
|
|
751
831
|
}
|
|
752
832
|
else {
|
|
833
|
+
// warn: document is to big to be parsed and folded, this is not a critical issue, just a ui problem
|
|
753
834
|
}
|
|
754
835
|
}
|
|
755
836
|
updateEditorContentHeight();
|
|
@@ -758,6 +839,12 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
758
839
|
editor.destroy();
|
|
759
840
|
};
|
|
760
841
|
}, [
|
|
842
|
+
// Make sure that this effect is never updated as this will cause the whole
|
|
843
|
+
// editor to re-mount causing weird behavior and possible performance
|
|
844
|
+
// bottlenecks
|
|
845
|
+
//
|
|
846
|
+
// All the following values are refs which will not change value after
|
|
847
|
+
// initial render and so will not re-trigger this effect
|
|
761
848
|
annotationsGutterExtension,
|
|
762
849
|
foldGutterExtension,
|
|
763
850
|
languageExtension,
|
|
@@ -772,15 +859,21 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
772
859
|
updateEditorContentHeight,
|
|
773
860
|
]);
|
|
774
861
|
(0, react_1.useEffect)(() => {
|
|
862
|
+
// Ignore changes to `text` prop if `initialText` was provided
|
|
775
863
|
if (initialTextProvided.current) {
|
|
776
864
|
return;
|
|
777
865
|
}
|
|
866
|
+
// When the outside value is out of sync with the editor value, hard reset
|
|
867
|
+
// the editor if we are in controlled mode (we might need to account for
|
|
868
|
+
// cursor position, but currently this sort of update can happen only on
|
|
869
|
+
// blur so we can ignore this for now)
|
|
778
870
|
if (editorViewRef.current &&
|
|
779
871
|
text !== (editorViewRef.current.state.sliceDoc() ?? '')) {
|
|
780
872
|
const controller = new AbortController();
|
|
781
873
|
void scheduleDispatch(editorViewRef.current, {
|
|
782
874
|
changes: {
|
|
783
875
|
from: 0,
|
|
876
|
+
// Replace all the content
|
|
784
877
|
to: editorViewRef.current.state.doc.length,
|
|
785
878
|
insert: text,
|
|
786
879
|
},
|
|
@@ -802,6 +895,15 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
802
895
|
controller.abort();
|
|
803
896
|
};
|
|
804
897
|
}, [annotations]);
|
|
898
|
+
// We wrap editor in a relatively positioned container followed by an absolute
|
|
899
|
+
// one to be able to create a new DOM layer that will prevent component
|
|
900
|
+
// changes from triggering pricey layout reflows for the whole document. We
|
|
901
|
+
// then manually keep conatiner height in sync with the editor height to make
|
|
902
|
+
// sure that the element actually takes all the required space in the page
|
|
903
|
+
// layout. This is a performance optimization that is mainly needed for the
|
|
904
|
+
// query bar component where typing anything in the editor might trigger a
|
|
905
|
+
// layout reflow for the whole document which causes .5s lag in the UI on
|
|
906
|
+
// every character input in worst case scenarios
|
|
805
907
|
(0, react_1.useLayoutEffect)(() => {
|
|
806
908
|
if (containerRef.current) {
|
|
807
909
|
const scrollHeight = hasScroll && showScroll ? 10 : 0;
|
|
@@ -817,6 +919,13 @@ const BaseEditor = react_1.default.forwardRef(function BaseEditor({ initialText:
|
|
|
817
919
|
maxHeight: '100%',
|
|
818
920
|
} },
|
|
819
921
|
react_1.default.createElement("div", { ref: editorContainerRef, className: (0, compass_components_1.cx)(editorStyle, !showScroll && hiddenScrollStyle), style: {
|
|
922
|
+
// We're forcing editor to it's own layer by setting position to
|
|
923
|
+
// absolute to prevent editor layout changes and style
|
|
924
|
+
// recalculations to cause layout reflows for the whole document
|
|
925
|
+
//
|
|
926
|
+
// Having position absolute here causes element to create it's
|
|
927
|
+
// own layer that keeps all pricey layout operations inside.
|
|
928
|
+
// This works in combination wit parent height update. See above
|
|
820
929
|
position: 'absolute',
|
|
821
930
|
width: '100%',
|
|
822
931
|
height: '100%',
|
|
@@ -856,12 +965,16 @@ const foldAll = (editor) => {
|
|
|
856
965
|
(0, language_1.foldable)(editor.state, nodeRef.from, nodeRef.to) &&
|
|
857
966
|
!isTopNode(nodeRef.node)) {
|
|
858
967
|
if (!nodeRef.node.parent) {
|
|
968
|
+
// isTopNode guarantees that we are not trying to fold something
|
|
969
|
+
// without a parent
|
|
859
970
|
throw new Error('Trying to fold node without parent');
|
|
860
971
|
}
|
|
861
972
|
const range = (0, language_1.foldInside)(nodeRef.node.parent);
|
|
862
973
|
if (range) {
|
|
863
974
|
foldableProperties.push(range);
|
|
864
975
|
}
|
|
976
|
+
// Returning `false` stops iteration over children, we don't need
|
|
977
|
+
// to iterate children if the node we entered is foldable
|
|
865
978
|
return false;
|
|
866
979
|
}
|
|
867
980
|
},
|
|
@@ -880,6 +993,7 @@ const copyAll = (editorView) => {
|
|
|
880
993
|
return true;
|
|
881
994
|
};
|
|
882
995
|
const prettify = (editorView) => {
|
|
996
|
+
// Can't prettify a read-only document
|
|
883
997
|
if (isReadOnly(editorView.state)) {
|
|
884
998
|
return false;
|
|
885
999
|
}
|
|
@@ -900,6 +1014,7 @@ const prettify = (editorView) => {
|
|
|
900
1014
|
}
|
|
901
1015
|
}
|
|
902
1016
|
catch {
|
|
1017
|
+
// failed to parse, do nothing
|
|
903
1018
|
}
|
|
904
1019
|
return false;
|
|
905
1020
|
};
|
|
@@ -958,6 +1073,9 @@ const MultilineEditor = react_1.default.forwardRef(function MultilineEditor({ cu
|
|
|
958
1073
|
applySnippet(template) {
|
|
959
1074
|
return editorRef.current?.applySnippet(template) ?? false;
|
|
960
1075
|
},
|
|
1076
|
+
cursorDocEnd() {
|
|
1077
|
+
return editorRef.current?.cursorDocEnd() ?? false;
|
|
1078
|
+
},
|
|
961
1079
|
startCompletion() {
|
|
962
1080
|
return editorRef.current?.startCompletion() ?? false;
|
|
963
1081
|
},
|
|
@@ -974,7 +1092,7 @@ const MultilineEditor = react_1.default.forwardRef(function MultilineEditor({ cu
|
|
|
974
1092
|
copyable && (react_1.default.createElement(actions_1.ActionButton, { key: "Copy", label: "Copy", icon: "Copy", onClick: () => {
|
|
975
1093
|
return editorRef.current?.copyAll() ?? false;
|
|
976
1094
|
} })),
|
|
977
|
-
formattable && (react_1.default.createElement(actions_1.ActionButton, { key: "Format", label: "Format", icon: react_1.default.createElement(actions_1.FormatIcon, { size: 14, role: "presentation" }), onClick: () => {
|
|
1095
|
+
formattable && (react_1.default.createElement(actions_1.ActionButton, { key: "Format", label: "Format", icon: react_1.default.createElement(actions_1.FormatIcon, { size: /* leafygreen small */ 14, role: "presentation" }), onClick: () => {
|
|
978
1096
|
return editorRef.current?.prettify() ?? false;
|
|
979
1097
|
} })),
|
|
980
1098
|
...(customActions ?? []).map((action) => {
|
|
@@ -987,7 +1105,14 @@ const MultilineEditor = react_1.default.forwardRef(function MultilineEditor({ cu
|
|
|
987
1105
|
}),
|
|
988
1106
|
];
|
|
989
1107
|
}, [copyable, formattable, customActions]);
|
|
990
|
-
return (
|
|
1108
|
+
return (
|
|
1109
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
|
1110
|
+
react_1.default.createElement("div", { ref: containerRef, className: (0, compass_components_1.cx)(multilineEditorContainerStyle, darkMode && multilineEditorContainerDarkModeStyle, !!actions.length && multilineEditorContainerWithActionsStyle, className),
|
|
1111
|
+
// We want folks to be able to click into the container element
|
|
1112
|
+
// they're using for the editor to focus the editor.
|
|
1113
|
+
onClick: (evt) => {
|
|
1114
|
+
// Only do this when root container of the editor is clicked (not
|
|
1115
|
+
// something inside it)
|
|
991
1116
|
if (evt.target === containerRef.current) {
|
|
992
1117
|
editorRef.current?.focus();
|
|
993
1118
|
}
|
|
@@ -996,6 +1121,14 @@ const MultilineEditor = react_1.default.forwardRef(function MultilineEditor({ cu
|
|
|
996
1121
|
actions.length > 0 && (react_1.default.createElement("div", { className: (0, compass_components_1.cx)('multiline-editor-actions', actionsContainerStyle, actionsClassName) }, actions))));
|
|
997
1122
|
});
|
|
998
1123
|
exports.CodemirrorMultilineEditor = MultilineEditor;
|
|
1124
|
+
/**
|
|
1125
|
+
* Sets the editor value, use this with RTL like this:
|
|
1126
|
+
*
|
|
1127
|
+
* ```
|
|
1128
|
+
* render(<Editor data-testid='my-editor' />);
|
|
1129
|
+
* setCodemirrorEditorValue(screen.getByTestId('editor-test-id'), 'my text');
|
|
1130
|
+
* ```
|
|
1131
|
+
*/
|
|
999
1132
|
async function setCodemirrorEditorValue(element, text) {
|
|
1000
1133
|
if (typeof element === 'string') {
|
|
1001
1134
|
element = document.querySelector(`[data-testid="${element}"]`);
|
|
@@ -1013,6 +1146,14 @@ async function setCodemirrorEditorValue(element, text) {
|
|
|
1013
1146
|
});
|
|
1014
1147
|
}
|
|
1015
1148
|
exports.setCodemirrorEditorValue = setCodemirrorEditorValue;
|
|
1149
|
+
/**
|
|
1150
|
+
* Retrieves the contents of an editor, use this with RTL like this:
|
|
1151
|
+
*
|
|
1152
|
+
* ```
|
|
1153
|
+
* render(<Editor data-testid='my-editor' />);
|
|
1154
|
+
* getCodemirrorEditorValue(screen.getByTestId('editor-test-id'));
|
|
1155
|
+
* ```
|
|
1156
|
+
*/
|
|
1016
1157
|
function getCodemirrorEditorValue(element) {
|
|
1017
1158
|
if (typeof element === 'string') {
|
|
1018
1159
|
element = document.querySelector(`[data-testid="${element}"]`);
|