Browse Source

Merge pull request #8039 from weseek/imprv/126529-129067-tab-indent

imprv: Indent with tab
reiji-h 2 years ago
parent
commit
687387fe1d

+ 4 - 0
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -19,6 +19,7 @@ import { toastError, toastSuccess } from '~/client/util/toastr';
 import { OptionsToSave } from '~/interfaces/page-operation';
 import { OptionsToSave } from '~/interfaces/page-operation';
 import { SocketEventName } from '~/interfaces/websocket';
 import { SocketEventName } from '~/interfaces/websocket';
 import {
 import {
+  useDefaultIndentSize,
   useCurrentPathname, useIsEnabledAttachTitleHeader,
   useCurrentPathname, useIsEnabledAttachTitleHeader,
   useIsEditable, useIsUploadableFile, useIsUploadableImage, useIsIndentSizeForced,
   useIsEditable, useIsUploadableFile, useIsUploadableImage, useIsIndentSizeForced,
 } from '~/stores/context';
 } from '~/stores/context';
@@ -103,6 +104,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { data: isSlackEnabled } = useIsSlackEnabled();
   const { data: isSlackEnabled } = useIsSlackEnabled();
   const { data: isIndentSizeForced } = useIsIndentSizeForced();
   const { data: isIndentSizeForced } = useIsIndentSizeForced();
   const { data: currentIndentSize, mutate: mutateCurrentIndentSize } = useCurrentIndentSize();
   const { data: currentIndentSize, mutate: mutateCurrentIndentSize } = useCurrentIndentSize();
+  const { data: defaultIndentSize } = useDefaultIndentSize();
   const { data: isUploadableFile } = useIsUploadableFile();
   const { data: isUploadableFile } = useIsUploadableFile();
   const { data: isUploadableImage } = useIsUploadableImage();
   const { data: isUploadableImage } = useIsUploadableImage();
   const { data: conflictDiffModalStatus, close: closeConflictDiffModal } = useConflictDiffModal();
   const { data: conflictDiffModalStatus, close: closeConflictDiffModal } = useConflictDiffModal();
@@ -518,6 +520,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   useEffect(() => {
   useEffect(() => {
     // do nothing if the indent size fixed
     // do nothing if the indent size fixed
     if (isIndentSizeForced == null || isIndentSizeForced) {
     if (isIndentSizeForced == null || isIndentSizeForced) {
+      mutateCurrentIndentSize(undefined);
       return;
       return;
     }
     }
 
 
@@ -572,6 +575,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
         <CodeMirrorEditorMain
         <CodeMirrorEditorMain
           onChange={markdownChangedHandler}
           onChange={markdownChangedHandler}
           onSave={saveWithShortcut}
           onSave={saveWithShortcut}
+          indentSize={currentIndentSize ?? defaultIndentSize}
         />
         />
       </div>
       </div>
       <div className="page-editor-preview-container flex-expand-vert d-none d-lg-flex">
       <div className="page-editor-preview-container flex-expand-vert d-none d-lg-flex">

+ 28 - 2
packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.tsx

@@ -1,7 +1,10 @@
 import {
 import {
-  forwardRef, useMemo, useRef,
+  forwardRef, useMemo, useRef, useEffect,
 } from 'react';
 } from 'react';
 
 
+import { defaultKeymap } from '@codemirror/commands';
+import { indentUnit } from '@codemirror/language';
+import { keymap } from '@codemirror/view';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 
 
 import { GlobalCodeMirrorEditorKey } from '../../consts';
 import { GlobalCodeMirrorEditorKey } from '../../consts';
@@ -21,12 +24,14 @@ const CodeMirrorEditorContainer = forwardRef<HTMLDivElement>((props, ref) => {
 type Props = {
 type Props = {
   editorKey: string | GlobalCodeMirrorEditorKey,
   editorKey: string | GlobalCodeMirrorEditorKey,
   onChange?: (value: string) => void,
   onChange?: (value: string) => void,
+  indentSize?: number,
 }
 }
 
 
 export const CodeMirrorEditor = (props: Props): JSX.Element => {
 export const CodeMirrorEditor = (props: Props): JSX.Element => {
   const {
   const {
     editorKey,
     editorKey,
     onChange,
     onChange,
+    indentSize,
   } = props;
   } = props;
 
 
   const containerRef = useRef(null);
   const containerRef = useRef(null);
@@ -36,7 +41,28 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
       onChange,
       onChange,
     };
     };
   }, [onChange]);
   }, [onChange]);
-  useCodeMirrorEditorIsolated(editorKey, containerRef.current, cmProps);
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey, containerRef.current, cmProps);
+
+  useEffect(() => {
+    const extension = keymap.of([
+      ...defaultKeymap,
+    ]);
+
+    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extension);
+    return cleanupFunction;
+
+  }, [codeMirrorEditor]);
+
+  useEffect(() => {
+    if (indentSize == null) {
+      return;
+    }
+    const extension = indentUnit.of(' '.repeat(indentSize));
+
+    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extension);
+    return cleanupFunction;
+
+  }, [codeMirrorEditor, indentSize]);
 
 
   return (
   return (
     <div className="flex-expand-vert">
     <div className="flex-expand-vert">

+ 3 - 1
packages/editor/src/components/CodeMirrorEditorMain.tsx

@@ -17,11 +17,12 @@ const additionalExtensions: Extension[] = [
 type Props = {
 type Props = {
   onChange?: (value: string) => void,
   onChange?: (value: string) => void,
   onSave?: () => void,
   onSave?: () => void,
+  indentSize?: number,
 }
 }
 
 
 export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
 export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
   const {
   const {
-    onSave, onChange,
+    onSave, onChange, indentSize,
   } = props;
   } = props;
 
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
@@ -60,6 +61,7 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
     <CodeMirrorEditor
     <CodeMirrorEditor
       editorKey={GlobalCodeMirrorEditorKey.MAIN}
       editorKey={GlobalCodeMirrorEditorKey.MAIN}
       onChange={onChange}
       onChange={onChange}
+      indentSize={indentSize}
     />
     />
   );
   );
 };
 };

+ 12 - 2
packages/editor/src/services/codemirror-editor/use-codemirror-editor/use-codemirror-editor.ts

@@ -1,9 +1,10 @@
 import { useMemo } from 'react';
 import { useMemo } from 'react';
 
 
+import { indentWithTab } from '@codemirror/commands';
 import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
 import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
 import { languages } from '@codemirror/language-data';
 import { languages } from '@codemirror/language-data';
 import { EditorState, type Extension } from '@codemirror/state';
 import { EditorState, type Extension } from '@codemirror/state';
-import { EditorView } from '@codemirror/view';
+import { keymap, EditorView } from '@codemirror/view';
 import { useCodeMirror, type UseCodeMirror } from '@uiw/react-codemirror';
 import { useCodeMirror, type UseCodeMirror } from '@uiw/react-codemirror';
 import deepmerge from 'ts-deepmerge';
 import deepmerge from 'ts-deepmerge';
 
 
@@ -28,6 +29,7 @@ export type UseCodeMirrorEditor = {
 
 
 const defaultExtensions: Extension[] = [
 const defaultExtensions: Extension[] = [
   markdown({ base: markdownLanguage, codeLanguages: languages }),
   markdown({ base: markdownLanguage, codeLanguages: languages }),
+  keymap.of([indentWithTab]),
 ];
 ];
 
 
 export const useCodeMirrorEditor = (props?: UseCodeMirror): UseCodeMirrorEditor => {
 export const useCodeMirrorEditor = (props?: UseCodeMirror): UseCodeMirrorEditor => {
@@ -35,7 +37,15 @@ export const useCodeMirrorEditor = (props?: UseCodeMirror): UseCodeMirrorEditor
   const mergedProps = useMemo<UseCodeMirror>(() => {
   const mergedProps = useMemo<UseCodeMirror>(() => {
     return deepmerge(
     return deepmerge(
       props ?? {},
       props ?? {},
-      { extensions: defaultExtensions },
+      {
+        extensions: defaultExtensions,
+        // Reset settings of react-codemirror.
+        // The extension defined first will be used, so it must be disabled here.
+        indentWithTab: false,
+        basicSetup: {
+          defaultKeymap: false,
+        },
+      },
     );
     );
   }, [props]);
   }, [props]);