renderer.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { HtmlElementNode } from 'rehype-toc';
  2. import { Key, SWRResponse } from 'swr';
  3. import useSWRImmutable from 'swr/immutable';
  4. import { RendererConfig } from '~/interfaces/services/renderer';
  5. import {
  6. RendererOptions,
  7. generateSimpleViewOptions, generatePreviewOptions, generateOthersOptions,
  8. generateViewOptions, generateTocOptions,
  9. } from '~/services/renderer/renderer';
  10. import { getGrowiFacade } from '~/utils/growi-facade';
  11. import {
  12. useCurrentPagePath, useCurrentPageTocNode, useRendererConfig,
  13. } from './context';
  14. interface ReactMarkdownOptionsGenerator {
  15. (config: RendererConfig): RendererOptions
  16. }
  17. // The base hook with common processes
  18. const _useOptionsBase = (
  19. rendererId: string, generator: ReactMarkdownOptionsGenerator,
  20. ): SWRResponse<RendererOptions, Error> => {
  21. const { data: rendererConfig } = useRendererConfig();
  22. const isAllDataValid = rendererConfig != null;
  23. const key = isAllDataValid
  24. ? [rendererId, rendererConfig]
  25. : null;
  26. const swrResult = useSWRImmutable<RendererOptions, Error>(key);
  27. if (isAllDataValid && swrResult.data == null) {
  28. swrResult.mutate(generator(rendererConfig));
  29. }
  30. // call useSWRImmutable again to foce to update cache
  31. return useSWRImmutable<RendererOptions, Error>(key);
  32. };
  33. export const useViewOptions = (storeTocNodeHandler: (toc: HtmlElementNode) => void): SWRResponse<RendererOptions, Error> => {
  34. const { data: currentPagePath } = useCurrentPagePath();
  35. const { data: rendererConfig } = useRendererConfig();
  36. const isAllDataValid = currentPagePath != null && rendererConfig != null;
  37. const key = isAllDataValid
  38. ? ['viewOptions', currentPagePath, rendererConfig]
  39. : null;
  40. return useSWRImmutable<RendererOptions, Error>(
  41. key,
  42. (rendererId, currentPagePath, rendererConfig) => generateViewOptions(currentPagePath, rendererConfig, storeTocNodeHandler),
  43. {
  44. fallbackData: isAllDataValid ? generateViewOptions(currentPagePath, rendererConfig, storeTocNodeHandler) : undefined,
  45. },
  46. );
  47. };
  48. export const useTocOptions = (): SWRResponse<RendererOptions, Error> => {
  49. const { data: currentPagePath } = useCurrentPagePath();
  50. const { data: rendererConfig } = useRendererConfig();
  51. const { data: tocNode } = useCurrentPageTocNode();
  52. const isAllDataValid = rendererConfig != null;
  53. const key = isAllDataValid
  54. ? ['tocOptions', currentPagePath, tocNode, rendererConfig]
  55. : null;
  56. return useSWRImmutable<RendererOptions, Error>(
  57. key,
  58. (rendererId, path, tocNode, rendererConfig) => generateTocOptions(rendererConfig, tocNode),
  59. );
  60. };
  61. export const usePreviewOptions = (): SWRResponse<RendererOptions, Error> => {
  62. const { data: currentPagePath } = useCurrentPagePath();
  63. const { data: rendererConfig } = useRendererConfig();
  64. const isAllDataValid = currentPagePath != null && rendererConfig != null;
  65. const key = isAllDataValid
  66. ? ['previewOptions', rendererConfig, currentPagePath]
  67. : null;
  68. return useSWRImmutable<RendererOptions, Error>(
  69. key,
  70. (rendererId, rendererConfig, pagePath, highlightKeywords) => {
  71. // determine options generator
  72. const optionsGenerator = getGrowiFacade().markdownRenderer?.optionsGenerators?.customGeneratePreviewOptions ?? generatePreviewOptions;
  73. return optionsGenerator(rendererConfig, pagePath, highlightKeywords);
  74. },
  75. {
  76. fallbackData: isAllDataValid ? generatePreviewOptions(rendererConfig, currentPagePath) : undefined,
  77. },
  78. );
  79. };
  80. export const useCommentForCurrentPageOptions = (): SWRResponse<RendererOptions, Error> => {
  81. const { data: currentPagePath } = useCurrentPagePath();
  82. const { data: rendererConfig } = useRendererConfig();
  83. const isAllDataValid = currentPagePath != null && rendererConfig != null;
  84. const key = isAllDataValid
  85. ? ['commentForCurrentPageOptions', rendererConfig, currentPagePath]
  86. : null;
  87. return useSWRImmutable<RendererOptions, Error>(
  88. key,
  89. (rendererId, rendererConfig, currentPagePath) => generateSimpleViewOptions(rendererConfig, currentPagePath),
  90. {
  91. fallbackData: isAllDataValid ? generateSimpleViewOptions(rendererConfig, currentPagePath) : undefined,
  92. },
  93. );
  94. };
  95. export const useCommentPreviewOptions = useCommentForCurrentPageOptions;
  96. export const useSelectedPagePreviewOptions = (pagePath: string, highlightKeywords?: string | string[]): SWRResponse<RendererOptions, Error> => {
  97. const { data: rendererConfig } = useRendererConfig();
  98. const isAllDataValid = rendererConfig != null;
  99. const key = isAllDataValid
  100. ? ['selectedPagePreviewOptions', rendererConfig, pagePath, highlightKeywords]
  101. : null;
  102. return useSWRImmutable<RendererOptions, Error>(
  103. key,
  104. (rendererId, rendererConfig, pagePath, highlightKeywords) => generateSimpleViewOptions(rendererConfig, pagePath, highlightKeywords),
  105. {
  106. fallbackData: isAllDataValid ? generateSimpleViewOptions(rendererConfig, pagePath, highlightKeywords) : undefined,
  107. },
  108. );
  109. };
  110. export const useSearchResultOptions = useSelectedPagePreviewOptions;
  111. export const useTimelineOptions = (): SWRResponse<RendererOptions, Error> => {
  112. const key = 'timelineOptions';
  113. return _useOptionsBase(key, generateOthersOptions);
  114. };
  115. export const useDraftOptions = (): SWRResponse<RendererOptions, Error> => {
  116. const key = 'draftOptions';
  117. return _useOptionsBase(key, generateOthersOptions);
  118. };
  119. export const useCustomSidebarOptions = (): SWRResponse<RendererOptions, Error> => {
  120. const key: Key = 'customSidebarOptions';
  121. return _useOptionsBase(key, generateOthersOptions);
  122. };