renderer.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { HtmlElementNode } from 'rehype-toc';
  2. import useSWR, { 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 useSWR<RendererOptions, Error>(
  41. key,
  42. (rendererId, currentPagePath, rendererConfig) => {
  43. // determine options generator
  44. const optionsGenerator = getGrowiFacade().markdownRenderer?.optionsGenerators?.customGenerateViewOptions ?? generateViewOptions;
  45. return optionsGenerator(currentPagePath, rendererConfig, storeTocNodeHandler);
  46. },
  47. {
  48. fallbackData: isAllDataValid ? generateViewOptions(currentPagePath, rendererConfig, storeTocNodeHandler) : undefined,
  49. },
  50. );
  51. };
  52. export const useTocOptions = (): SWRResponse<RendererOptions, Error> => {
  53. const { data: currentPagePath } = useCurrentPagePath();
  54. const { data: rendererConfig } = useRendererConfig();
  55. const { data: tocNode } = useCurrentPageTocNode();
  56. const isAllDataValid = rendererConfig != null;
  57. const key = isAllDataValid
  58. ? ['tocOptions', currentPagePath, tocNode, rendererConfig]
  59. : null;
  60. return useSWRImmutable<RendererOptions, Error>(
  61. key,
  62. (rendererId, path, tocNode, rendererConfig) => generateTocOptions(rendererConfig, tocNode),
  63. );
  64. };
  65. export const usePreviewOptions = (): SWRResponse<RendererOptions, Error> => {
  66. const { data: currentPagePath } = useCurrentPagePath();
  67. const { data: rendererConfig } = useRendererConfig();
  68. const isAllDataValid = currentPagePath != null && rendererConfig != null;
  69. const key = isAllDataValid
  70. ? ['previewOptions', rendererConfig, currentPagePath]
  71. : null;
  72. return useSWR<RendererOptions, Error>(
  73. key,
  74. (rendererId, rendererConfig, pagePath, highlightKeywords) => {
  75. // determine options generator
  76. const optionsGenerator = getGrowiFacade().markdownRenderer?.optionsGenerators?.customGeneratePreviewOptions ?? generatePreviewOptions;
  77. return optionsGenerator(rendererConfig, pagePath, highlightKeywords);
  78. },
  79. {
  80. fallbackData: isAllDataValid ? generatePreviewOptions(rendererConfig, currentPagePath) : undefined,
  81. },
  82. );
  83. };
  84. export const useCommentForCurrentPageOptions = (): SWRResponse<RendererOptions, Error> => {
  85. const { data: currentPagePath } = useCurrentPagePath();
  86. const { data: rendererConfig } = useRendererConfig();
  87. const isAllDataValid = currentPagePath != null && rendererConfig != null;
  88. const key = isAllDataValid
  89. ? ['commentForCurrentPageOptions', rendererConfig, currentPagePath]
  90. : null;
  91. return useSWRImmutable<RendererOptions, Error>(
  92. key,
  93. (rendererId, rendererConfig, currentPagePath) => generateSimpleViewOptions(rendererConfig, currentPagePath),
  94. {
  95. fallbackData: isAllDataValid ? generateSimpleViewOptions(rendererConfig, currentPagePath) : undefined,
  96. },
  97. );
  98. };
  99. export const useCommentPreviewOptions = useCommentForCurrentPageOptions;
  100. export const useSelectedPagePreviewOptions = (pagePath: string, highlightKeywords?: string | string[]): SWRResponse<RendererOptions, Error> => {
  101. const { data: rendererConfig } = useRendererConfig();
  102. const isAllDataValid = rendererConfig != null;
  103. const key = isAllDataValid
  104. ? ['selectedPagePreviewOptions', rendererConfig, pagePath, highlightKeywords]
  105. : null;
  106. return useSWRImmutable<RendererOptions, Error>(
  107. key,
  108. (rendererId, rendererConfig, pagePath, highlightKeywords) => generateSimpleViewOptions(rendererConfig, pagePath, highlightKeywords),
  109. {
  110. fallbackData: isAllDataValid ? generateSimpleViewOptions(rendererConfig, pagePath, highlightKeywords) : undefined,
  111. },
  112. );
  113. };
  114. export const useSearchResultOptions = useSelectedPagePreviewOptions;
  115. export const useTimelineOptions = (): SWRResponse<RendererOptions, Error> => {
  116. const key = 'timelineOptions';
  117. return _useOptionsBase(key, generateOthersOptions);
  118. };
  119. export const useDraftOptions = (): SWRResponse<RendererOptions, Error> => {
  120. const key = 'draftOptions';
  121. return _useOptionsBase(key, generateOthersOptions);
  122. };
  123. export const useCustomSidebarOptions = (): SWRResponse<RendererOptions, Error> => {
  124. const key: Key = 'customSidebarOptions';
  125. return _useOptionsBase(key, generateOthersOptions);
  126. };