Preview.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import React, {
  2. useCallback, useEffect, useMemo, useState, SyntheticEvent,
  3. } from 'react';
  4. import AppContainer from '~/client/services/AppContainer';
  5. import { useEditorSettings } from '~/stores/editor';
  6. import RevisionBody from '../Page/RevisionBody';
  7. import { withUnstatedContainers } from '../UnstatedUtils';
  8. type Props = {
  9. appContainer: AppContainer,
  10. markdown?: string,
  11. pagePath?: string,
  12. inputRef?: React.RefObject<HTMLDivElement>,
  13. isMathJaxEnabled?: boolean,
  14. renderMathJaxOnInit?: boolean,
  15. onScroll?: (scrollTop: number) => void,
  16. }
  17. const Preview = (props: Props): JSX.Element => {
  18. const {
  19. appContainer,
  20. markdown, pagePath,
  21. inputRef,
  22. } = props;
  23. const [html, setHtml] = useState('');
  24. const { data: editorSettings } = useEditorSettings();
  25. const { interceptorManager } = appContainer;
  26. const growiRenderer = props.appContainer.getRenderer('editor');
  27. const context = useMemo(() => {
  28. return {
  29. markdown,
  30. pagePath,
  31. renderDrawioInRealtime: editorSettings?.renderDrawioInRealtime,
  32. currentPathname: decodeURIComponent(window.location.pathname),
  33. parsedHTML: null,
  34. };
  35. }, [markdown, pagePath, editorSettings?.renderDrawioInRealtime]);
  36. const renderPreview = useCallback(async() => {
  37. if (interceptorManager != null) {
  38. await interceptorManager.process('preRenderPreview', context);
  39. await interceptorManager.process('prePreProcess', context);
  40. context.markdown = growiRenderer.preProcess(context.markdown, context);
  41. await interceptorManager.process('postPreProcess', context);
  42. context.parsedHTML = growiRenderer.process(context.markdown, context);
  43. await interceptorManager.process('prePostProcess', context);
  44. context.parsedHTML = growiRenderer.postProcess(context.parsedHTML, context);
  45. await interceptorManager.process('postPostProcess', context);
  46. await interceptorManager.process('preRenderPreviewHtml', context);
  47. }
  48. setHtml(context.parsedHTML ?? '');
  49. }, [interceptorManager, context, growiRenderer]);
  50. useEffect(() => {
  51. if (markdown == null) {
  52. setHtml('');
  53. }
  54. renderPreview();
  55. }, [markdown, renderPreview]);
  56. useEffect(() => {
  57. if (html == null) {
  58. return;
  59. }
  60. if (interceptorManager != null) {
  61. interceptorManager.process('postRenderPreviewHtml', {
  62. ...context,
  63. parsedHTML: html,
  64. });
  65. }
  66. }, [context, html, interceptorManager]);
  67. return (
  68. <div
  69. className="page-editor-preview-body"
  70. ref={inputRef}
  71. onScroll={(event: SyntheticEvent<HTMLDivElement>) => {
  72. if (props.onScroll != null) {
  73. props.onScroll(event.currentTarget.scrollTop);
  74. }
  75. }}
  76. >
  77. <RevisionBody
  78. {...props}
  79. html={html}
  80. renderMathJaxInRealtime={editorSettings?.renderMathJaxInRealtime}
  81. />
  82. </div>
  83. );
  84. };
  85. /**
  86. * Wrapper component for using unstated
  87. */
  88. const PreviewWrapper = withUnstatedContainers(Preview, [AppContainer]);
  89. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  90. const PreviewWrapper2 = (props): JSX.Element => {
  91. return <PreviewWrapper {...props} />;
  92. };
  93. export default PreviewWrapper2;