@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.
Files changed (41) hide show
  1. package/dist/actions.js +2 -0
  2. package/dist/actions.js.map +1 -1
  3. package/dist/codemirror/ace-compat-autocompleter.d.ts +12 -0
  4. package/dist/codemirror/ace-compat-autocompleter.d.ts.map +1 -1
  5. package/dist/codemirror/ace-compat-autocompleter.js +18 -0
  6. package/dist/codemirror/ace-compat-autocompleter.js.map +1 -1
  7. package/dist/codemirror/aggregation-autocompleter.js +2 -0
  8. package/dist/codemirror/aggregation-autocompleter.js.map +1 -1
  9. package/dist/codemirror/document-autocompleter.d.ts +4 -0
  10. package/dist/codemirror/document-autocompleter.d.ts.map +1 -1
  11. package/dist/codemirror/document-autocompleter.js +16 -2
  12. package/dist/codemirror/document-autocompleter.js.map +1 -1
  13. package/dist/codemirror/query-autocompleter-with-history.d.ts +7 -1
  14. package/dist/codemirror/query-autocompleter-with-history.d.ts.map +1 -1
  15. package/dist/codemirror/query-autocompleter-with-history.js +8 -2
  16. package/dist/codemirror/query-autocompleter-with-history.js.map +1 -1
  17. package/dist/codemirror/query-autocompleter.d.ts +4 -0
  18. package/dist/codemirror/query-autocompleter.d.ts.map +1 -1
  19. package/dist/codemirror/query-autocompleter.js +4 -0
  20. package/dist/codemirror/query-autocompleter.js.map +1 -1
  21. package/dist/codemirror/query-history-autocompleter.d.ts +8 -2
  22. package/dist/codemirror/query-history-autocompleter.d.ts.map +1 -1
  23. package/dist/codemirror/query-history-autocompleter.js +91 -13
  24. package/dist/codemirror/query-history-autocompleter.js.map +1 -1
  25. package/dist/codemirror/stage-autocompleter.js +1 -0
  26. package/dist/codemirror/stage-autocompleter.js.map +1 -1
  27. package/dist/codemirror/utils.d.ts +5 -0
  28. package/dist/codemirror/utils.d.ts.map +1 -1
  29. package/dist/codemirror/utils.js +16 -0
  30. package/dist/codemirror/utils.js.map +1 -1
  31. package/dist/codemirror/validation-autocompleter.js +15 -0
  32. package/dist/codemirror/validation-autocompleter.js.map +1 -1
  33. package/dist/editor.d.ts +19 -2
  34. package/dist/editor.d.ts.map +1 -1
  35. package/dist/editor.js +144 -3
  36. package/dist/editor.js.map +1 -1
  37. package/dist/prettify.js +5 -1
  38. package/dist/prettify.js.map +1 -1
  39. package/dist/types.d.ts +3 -0
  40. package/dist/types.d.ts.map +1 -1
  41. 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":"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"}
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
- declare function setCodemirrorEditorValue(element: HTMLElement | string | null, text: string): Promise<void>;
134
- declare function getCodemirrorEditorValue(element: HTMLElement | string | null): string;
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 };
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"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"}
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: '70vh',
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 (react_1.default.createElement("div", { ref: containerRef, className: (0, compass_components_1.cx)(multilineEditorContainerStyle, darkMode && multilineEditorContainerDarkModeStyle, !!actions.length && multilineEditorContainerWithActionsStyle, className), onClick: (evt) => {
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}"]`);