|
|
@@ -1,6 +1,7 @@
|
|
|
-import type { JSX } from 'react';
|
|
|
+import { type JSX, useMemo } from 'react';
|
|
|
import Head from 'next/head';
|
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
+import type { PluggableList } from 'unified';
|
|
|
|
|
|
import { MARP_CONTAINER_CLASS_NAME, type PresentationOptions } from '../consts';
|
|
|
import {
|
|
|
@@ -23,25 +24,36 @@ export const GrowiSlides = (props: Props): JSX.Element => {
|
|
|
const { options, children, presentation } = props;
|
|
|
const { rendererOptions, isDarkMode, disableSeparationByHeader } = options;
|
|
|
|
|
|
- if (
|
|
|
- rendererOptions.remarkPlugins == null ||
|
|
|
- rendererOptions.components == null
|
|
|
- ) {
|
|
|
- // biome-ignore lint/complexity/noUselessFragments: This is for type checking only. The actual code will never reach here.
|
|
|
+ // Derive a new options object instead of mutating `rendererOptions`:
|
|
|
+ // it is a shared SWR cache reference also consumed by PagePresentationModal,
|
|
|
+ // so mutation here would leak into other components and accumulate on re-render.
|
|
|
+ const slideRendererOptions = useMemo(() => {
|
|
|
+ if (
|
|
|
+ rendererOptions == null ||
|
|
|
+ rendererOptions.remarkPlugins == null ||
|
|
|
+ rendererOptions.components == null
|
|
|
+ ) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const remarkPlugins: PluggableList = [
|
|
|
+ ...rendererOptions.remarkPlugins,
|
|
|
+ [extractSections.remarkPlugin, { isDarkMode, disableSeparationByHeader }],
|
|
|
+ ];
|
|
|
+ return {
|
|
|
+ ...rendererOptions,
|
|
|
+ remarkPlugins,
|
|
|
+ components: {
|
|
|
+ ...rendererOptions.components,
|
|
|
+ section: presentation ? PresentationRichSlideSection : RichSlideSection,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ }, [rendererOptions, isDarkMode, disableSeparationByHeader, presentation]);
|
|
|
+
|
|
|
+ if (slideRendererOptions == null) {
|
|
|
+ // biome-ignore lint/complexity/noUselessFragments: early return when rendererOptions is null
|
|
|
return <></>;
|
|
|
}
|
|
|
|
|
|
- rendererOptions.remarkPlugins.push([
|
|
|
- extractSections.remarkPlugin,
|
|
|
- {
|
|
|
- isDarkMode,
|
|
|
- disableSeparationByHeader,
|
|
|
- },
|
|
|
- ]);
|
|
|
- rendererOptions.components.section = presentation
|
|
|
- ? PresentationRichSlideSection
|
|
|
- : RichSlideSection;
|
|
|
-
|
|
|
const css = presentation ? PRESENTATION_MARPIT_CSS : SLIDE_MARPIT_CSS;
|
|
|
return (
|
|
|
<>
|
|
|
@@ -49,7 +61,7 @@ export const GrowiSlides = (props: Props): JSX.Element => {
|
|
|
<style>{css}</style>
|
|
|
</Head>
|
|
|
<div className={`slides ${MARP_CONTAINER_CLASS_NAME}`}>
|
|
|
- <ReactMarkdown {...rendererOptions}>
|
|
|
+ <ReactMarkdown {...slideRendererOptions}>
|
|
|
{children ?? '## No Contents'}
|
|
|
</ReactMarkdown>
|
|
|
</div>
|