CodeMirrorEditorMain.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { useEffect, useMemo, type JSX } from 'react';
  2. import { type Extension } from '@codemirror/state';
  3. import { keymap, scrollPastEnd } from '@codemirror/view';
  4. import type { IUserHasId } from '@growi/core/dist/interfaces';
  5. import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
  6. import deepmerge from 'ts-deepmerge';
  7. import { GlobalCodeMirrorEditorKey } from '../../consts';
  8. import type { EditingClient } from '../../interfaces';
  9. import { CodeMirrorEditor, type CodeMirrorEditorProps } from '../components-internal/CodeMirrorEditor';
  10. import { setDataLine, useUnifiedMergeView, codemirrorEditorClassForUnifiedMergeView } from '../services-internal';
  11. import { useCodeMirrorEditorIsolated } from '../stores/codemirror-editor';
  12. import { useCollaborativeEditorMode } from '../stores/use-collaborative-editor-mode';
  13. const additionalExtensions: Extension[] = [
  14. [
  15. scrollPastEnd(),
  16. setDataLine,
  17. ],
  18. ];
  19. type Props = CodeMirrorEditorProps & {
  20. user?: IUserHasId,
  21. pageId?: string,
  22. initialValue?: string,
  23. enableCollaboration?: boolean,
  24. enableUnifiedMergeView?: boolean,
  25. onEditorsUpdated?: (clientList: EditingClient[]) => void,
  26. }
  27. export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
  28. const {
  29. user, pageId,
  30. enableCollaboration = false, enableUnifiedMergeView = false,
  31. cmProps,
  32. onSave, onEditorsUpdated, ...otherProps
  33. } = props;
  34. const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
  35. useCollaborativeEditorMode(enableCollaboration, codeMirrorEditor, {
  36. user,
  37. pageId,
  38. onEditorsUpdated,
  39. reviewMode: enableUnifiedMergeView,
  40. });
  41. useUnifiedMergeView(enableUnifiedMergeView, codeMirrorEditor, { pageId });
  42. // setup additional extensions
  43. useEffect(() => {
  44. return codeMirrorEditor?.appendExtensions?.(additionalExtensions);
  45. }, [codeMirrorEditor]);
  46. // set handler to save with shortcut key
  47. useEffect(() => {
  48. if (onSave == null) {
  49. return;
  50. }
  51. const extension = keymap.of([
  52. {
  53. key: 'Mod-s',
  54. preventDefault: true,
  55. run: () => {
  56. const doc = codeMirrorEditor?.getDoc();
  57. if (doc != null) {
  58. onSave();
  59. }
  60. return true;
  61. },
  62. },
  63. ]);
  64. const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extension);
  65. return cleanupFunction;
  66. }, [codeMirrorEditor, onSave]);
  67. const cmPropsOverride = useMemo<ReactCodeMirrorProps>(() => deepmerge(
  68. cmProps ?? {},
  69. {
  70. // Disable the basic history configuration since this component uses Y.UndoManager instead
  71. basicSetup: {
  72. history: false,
  73. },
  74. },
  75. ), [cmProps]);
  76. return (
  77. <CodeMirrorEditor
  78. editorKey={GlobalCodeMirrorEditorKey.MAIN}
  79. className={codemirrorEditorClassForUnifiedMergeView}
  80. onSave={onSave}
  81. cmProps={cmPropsOverride}
  82. {...otherProps}
  83. />
  84. );
  85. };