CodeMirrorEditorMain.tsx 2.9 KB

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