codemirror-editor.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { useMemo, useRef } from 'react';
  2. import { type Extension } from '@codemirror/state';
  3. import { scrollPastEnd } from '@codemirror/view';
  4. import { useSWRStatic } from '@growi/core/dist/swr';
  5. import type { ReactCodeMirrorProps, UseCodeMirror } from '@uiw/react-codemirror';
  6. import type { SWRResponse } from 'swr';
  7. import type { UseCodeMirrorEditor } from '../services';
  8. import { useCodeMirrorEditor } from '../services';
  9. const isValid = (u: UseCodeMirrorEditor) => {
  10. return u.state != null && u.view != null;
  11. };
  12. const isDeepEquals = <T extends object>(obj1: T, obj2: T): boolean => {
  13. const typedKeys = Object.keys(obj1) as (keyof typeof obj1)[];
  14. return typedKeys.every(key => obj1[key] === obj2[key]);
  15. };
  16. const defaultExtensionsMain: Extension[] = [
  17. scrollPastEnd(),
  18. ];
  19. export const useCodeMirrorEditorIsolated = (
  20. key?: string, container?: HTMLDivElement | null, props?: ReactCodeMirrorProps,
  21. ): SWRResponse<UseCodeMirrorEditor> => {
  22. const ref = useRef<UseCodeMirrorEditor>();
  23. const currentData = ref.current;
  24. const swrKey = key != null ? `codeMirrorEditor_${key}` : null;
  25. const mergedProps = useMemo<UseCodeMirror>(() => {
  26. return {
  27. ...props,
  28. container,
  29. extensions: [
  30. ...(props?.extensions ?? []),
  31. ...defaultExtensionsMain,
  32. ],
  33. };
  34. }, [container, props]);
  35. const newData = useCodeMirrorEditor(mergedProps);
  36. const shouldUpdate = swrKey != null && container != null && props != null && (
  37. currentData == null
  38. || (isValid(newData) && !isDeepEquals(currentData, newData))
  39. );
  40. if (shouldUpdate) {
  41. ref.current = newData;
  42. // eslint-disable-next-line no-console
  43. console.info('Initializing codemirror for main');
  44. }
  45. return useSWRStatic(swrKey, shouldUpdate ? newData : undefined);
  46. };