Просмотр исходного кода

impl extractChildrenToIgnoreReactNode

Yuki Takei 3 лет назад
Родитель
Сommit
dcfc8139a0
1 измененных файлов с 57 добавлено и 22 удалено
  1. 57 22
      packages/app/src/components/ReactMarkdownComponents/CodeBlock.tsx

+ 57 - 22
packages/app/src/components/ReactMarkdownComponents/CodeBlock.tsx

@@ -1,4 +1,4 @@
-import { useMemo } from 'react';
+import { ReactNode } from 'react';
 
 import type { CodeComponent } from 'react-markdown/lib/ast-to-react';
 import { PrismAsyncLight } from 'react-syntax-highlighter';
@@ -6,12 +6,62 @@ import { oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
 
 import styles from './CodeBlock.module.scss';
 
-export const CodeBlock: CodeComponent = ({ inline, className, children }) => {
 
-  const isHighlightedByElasticsearch = useMemo((): boolean => {
-    const hasOnlyOneStringChild = children.length === 1 && typeof children[0] === 'string';
-    return !hasOnlyOneStringChild;
-  }, [children]);
+function extractChildrenToIgnoreReactNode(children: ReactNode): ReactNode {
+
+  if (children == null) {
+    return children;
+  }
+
+  // Single element array
+  if (Array.isArray(children) && children.length === 1) {
+    return extractChildrenToIgnoreReactNode(children[0]);
+  }
+
+  // Multiple element array
+  if (Array.isArray(children) && children.length > 1) {
+    return children.map(node => extractChildrenToIgnoreReactNode(node)).join('');
+  }
+
+  // object
+  if (typeof children === 'object') {
+    const grandChildren = (children as any).children ?? (children as any).props.children;
+    return extractChildrenToIgnoreReactNode(grandChildren);
+  }
+
+  return String(children).replace(/\n$/, '');
+}
+
+function CodeBlockSubstance({ lang, children }: { lang: string, children: ReactNode }): JSX.Element {
+  // return alternative element
+  //   in order to fix "CodeBlock string is be [object Object] if searched"
+  // see: https://github.com/weseek/growi/pull/7484
+  //
+  // Note: You can also remove this code if the user requests to see the code highlighted in Prism as-is.
+  const isSimpleString = Array.isArray(children) && children.length === 1 && typeof children[0] === 'string';
+  if (!isSimpleString) {
+    return (
+      <div className="code-highlighted" style={oneDark['pre[class*="language-"]']}>
+        <code className={`language-${lang}`} style={oneDark['code[class*="language-"]']}>
+          {children}
+        </code>
+      </div>
+    );
+  }
+
+  return (
+    <PrismAsyncLight
+      className="code-highlighted"
+      PreTag="div"
+      style={oneDark}
+      language={lang}
+    >
+      {extractChildrenToIgnoreReactNode(children)}
+    </PrismAsyncLight>
+  );
+}
+
+export const CodeBlock: CodeComponent = ({ inline, className, children }) => {
 
   if (inline) {
     return <code className={`code-inline ${className ?? ''}`}>{children}</code>;
@@ -28,22 +78,7 @@ export const CodeBlock: CodeComponent = ({ inline, className, children }) => {
       {name != null && (
         <cite className={`code-highlighted-title ${styles['code-highlighted-title']}`}>{name}</cite>
       )}
-      {isHighlightedByElasticsearch ? (
-        <div className="code-highlighted" style={oneDark['pre[class*="language-"]']}>
-          <code className={`language-${lang}`} style={oneDark['code[class*="language-"]']}>
-            {children}
-          </code>
-        </div>
-      ) : (
-        <PrismAsyncLight
-          className="code-highlighted"
-          PreTag="div"
-          style={oneDark}
-          language={lang}
-        >
-          {String(children).replace(/\n$/, '')}
-        </PrismAsyncLight>
-      )}
+      <CodeBlockSubstance lang={lang}>{children}</CodeBlockSubstance>
     </>
   );
 };