Preview.tsx 3.4 KB

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