use-editor-settings.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import { useEffect, useCallback, useState } from 'react';
  2. import type { Extension } from '@codemirror/state';
  3. import { Prec } from '@codemirror/state';
  4. import {
  5. keymap, type Command, highlightActiveLine, highlightActiveLineGutter,
  6. } from '@codemirror/view';
  7. import {
  8. type EditorSettings, type KeyMapMode, type EditorTheme,
  9. } from '../../consts';
  10. import type { UseCodeMirrorEditor } from '../services';
  11. import {
  12. getEditorTheme, getKeymap, insertNewlineContinueMarkup, insertNewRowToMarkdownTable, isInTable,
  13. } from '../services-internal';
  14. import { useKeyBindings, useKeyboardShortcuts, useCustomKeyBindings } from './use-editor-shortcuts';
  15. export const useEditorSettings = (
  16. codeMirrorEditor?: UseCodeMirrorEditor,
  17. editorSettings?: EditorSettings,
  18. onSave?: () => void,
  19. ): void => {
  20. useEffect(() => {
  21. if (editorSettings?.styleActiveLine == null) {
  22. return;
  23. }
  24. const extensions = (editorSettings?.styleActiveLine) ? [[highlightActiveLine(), highlightActiveLineGutter()]] : [[]];
  25. const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extensions);
  26. return cleanupFunction;
  27. }, [codeMirrorEditor, editorSettings?.styleActiveLine]);
  28. const onPressEnter: Command = useCallback((editor) => {
  29. if (isInTable(editor) && editorSettings?.autoFormatMarkdownTable) {
  30. insertNewRowToMarkdownTable(editor);
  31. return true;
  32. }
  33. insertNewlineContinueMarkup(editor);
  34. return true;
  35. }, [editorSettings?.autoFormatMarkdownTable]);
  36. useEffect(() => {
  37. const extension = keymap.of([
  38. { key: 'Enter', run: onPressEnter },
  39. ]);
  40. const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extension);
  41. return cleanupFunction;
  42. }, [codeMirrorEditor, onPressEnter]);
  43. const [themeExtension, setThemeExtension] = useState<Extension | undefined>(undefined);
  44. useEffect(() => {
  45. const settingTheme = async(name?: EditorTheme) => {
  46. setThemeExtension(await getEditorTheme(name));
  47. };
  48. settingTheme(editorSettings?.theme);
  49. }, [codeMirrorEditor, editorSettings?.theme, setThemeExtension]);
  50. useEffect(() => {
  51. if (themeExtension == null) {
  52. return;
  53. }
  54. // React CodeMirror has default theme which is default prec
  55. // and extension have to be higher prec here than default theme.
  56. const cleanupFunction = codeMirrorEditor?.appendExtensions(Prec.high(themeExtension));
  57. return cleanupFunction;
  58. }, [codeMirrorEditor, themeExtension]);
  59. const [keymapExtension, setKeymapExtension] = useState<Extension | undefined>(undefined);
  60. useEffect(() => {
  61. const settingKeyMap = async(name?: KeyMapMode) => {
  62. setKeymapExtension(await getKeymap(name, onSave));
  63. };
  64. settingKeyMap(editorSettings?.keymapMode);
  65. }, [codeMirrorEditor, editorSettings?.keymapMode, setKeymapExtension, onSave]);
  66. useEffect(() => {
  67. if (keymapExtension == null) {
  68. return;
  69. }
  70. // Prevent these Keybind from overwriting the originally defined keymap.
  71. const cleanupFunction = codeMirrorEditor?.appendExtensions(Prec.low(keymapExtension));
  72. return cleanupFunction;
  73. }, [codeMirrorEditor, keymapExtension]);
  74. const customKeyBindings = useCustomKeyBindings(codeMirrorEditor?.view, editorSettings?.keymapMode);
  75. const keyBindings = useKeyBindings(codeMirrorEditor?.view, customKeyBindings);
  76. useKeyboardShortcuts(codeMirrorEditor, keyBindings);
  77. };