This is an automated email from the ASF dual-hosted git repository.

robin0716 pushed a commit to branch feat/embed
in repository https://gitbox.apache.org/repos/asf/incubator-answer-plugins.git


The following commit(s) were added to refs/heads/feat/embed by this push:
     new 698f8fa  refactor(embed-basic): Implement the embed plugin with JSX 
and add loading status
698f8fa is described below

commit 698f8facf5d4103f767f43fe7bfbe5e41b16b3c8
Author: robin <[email protected]>
AuthorDate: Fri Jun 7 15:25:19 2024 +0800

    refactor(embed-basic): Implement the embed plugin with JSX and add loading 
status
---
 embed-basic/components/CodePenEmbed/index.tsx    | 37 ++++++++++++
 embed-basic/components/DropboxEmbed/index.tsx    | 36 ++++++++++++
 embed-basic/components/EmbedContainer/index.tsx  | 58 +++++++++++++++++++
 embed-basic/components/ExcalidrawEmbed/index.tsx | 36 ++++++++++++
 embed-basic/components/FigmaEmbed/index.tsx      | 35 ++++++++++++
 embed-basic/components/GithubGistEmbed/index.tsx | 33 +++++++++++
 embed-basic/components/JSFiddleEmbed/index.tsx   | 35 ++++++++++++
 embed-basic/components/LoomEmbed/index.tsx       | 36 ++++++++++++
 embed-basic/components/TwitterEmbed/index.tsx    | 71 ++++++++++++++++++++++++
 embed-basic/components/YouTubeEmbed/index.tsx    | 37 ++++++++++++
 embed-basic/components/index.ts                  | 40 +++++++++++++
 embed-basic/{hooks.ts => hooks.tsx}              | 70 ++++++++++++-----------
 12 files changed, 493 insertions(+), 31 deletions(-)

diff --git a/embed-basic/components/CodePenEmbed/index.tsx 
b/embed-basic/components/CodePenEmbed/index.tsx
new file mode 100644
index 0000000..2632d5d
--- /dev/null
+++ b/embed-basic/components/CodePenEmbed/index.tsx
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const CodePenEmbed = ({ penId }) => {
+  return (
+    <EmbedContainer>
+      <iframe
+        width="100%"
+        height="100%"
+        
src={`https://codepen.io/${penId}/embed/preview/${penId}?height=265&theme-id=0&default-tab=result`}
+        title="CodePen Embed"
+        allowTransparency
+        allowFullScreen
+      />
+    </EmbedContainer>
+  );
+};
+
+export default CodePenEmbed;
diff --git a/embed-basic/components/DropboxEmbed/index.tsx 
b/embed-basic/components/DropboxEmbed/index.tsx
new file mode 100644
index 0000000..9c678e3
--- /dev/null
+++ b/embed-basic/components/DropboxEmbed/index.tsx
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const DropboxEmbed = ({ dropboxId }) => {
+  return (
+    <EmbedContainer height={380}>
+      <iframe
+        title="Dropbox"
+        width="100%"
+        height="100%"
+        src={`https://www.dropbox.com/s/${dropboxId}?raw=1`}
+        frameBorder="0"
+      />
+    </EmbedContainer>
+  );
+};
+
+export default DropboxEmbed;
diff --git a/embed-basic/components/EmbedContainer/index.tsx 
b/embed-basic/components/EmbedContainer/index.tsx
new file mode 100644
index 0000000..224584f
--- /dev/null
+++ b/embed-basic/components/EmbedContainer/index.tsx
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { FC, cloneElement, useRef } from 'react';
+import Spinner from 'react-bootstrap/Spinner';
+
+interface EmbedContainerProps {
+  children: React.ReactElement;
+  height?: number | string;
+}
+const EmbedContainer: FC<EmbedContainerProps> = ({
+  children,
+  height = 350,
+}) => {
+  const loadingRef = useRef<HTMLSpanElement>(null);
+
+  const handleLoad = () => {
+    if (loadingRef.current) {
+      const parentElement = loadingRef.current.parentElement;
+      if (parentElement) {
+        parentElement.style.height = height + 'px';
+      }
+      loadingRef.current.remove();
+    }
+  };
+  let Component = children;
+  if (children.type === 'iframe') {
+    Component = cloneElement(children, { onLoad: handleLoad });
+  }
+  return (
+    <>
+      {Component}
+      <span
+        ref={loadingRef}
+        className="loading position-absolute top-0 left-0 w-100 h-100 z-1 
bg-white d-flex justify-content-center align-items-center">
+        <Spinner animation="border" variant="secondary" />
+      </span>
+    </>
+  );
+};
+
+export default EmbedContainer;
diff --git a/embed-basic/components/ExcalidrawEmbed/index.tsx 
b/embed-basic/components/ExcalidrawEmbed/index.tsx
new file mode 100644
index 0000000..1a659bf
--- /dev/null
+++ b/embed-basic/components/ExcalidrawEmbed/index.tsx
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const ExcalidrawEmbed = ({ excalidrawId }) => {
+  return (
+    <EmbedContainer height={380}>
+      <iframe
+        title="Excalidraw"
+        width="100%"
+        height="100%"
+        src={`https://excalidraw.com/${excalidrawId}/embed`}
+        frameBorder="0"
+      />
+    </EmbedContainer>
+  );
+};
+
+export default ExcalidrawEmbed;
diff --git a/embed-basic/components/FigmaEmbed/index.tsx 
b/embed-basic/components/FigmaEmbed/index.tsx
new file mode 100644
index 0000000..14cb644
--- /dev/null
+++ b/embed-basic/components/FigmaEmbed/index.tsx
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const FigmaEmbed = ({ url }) => {
+  return (
+    <EmbedContainer height={450}>
+      <iframe
+        style={{ border: 'none' }}
+        width="100%"
+        height="100%"
+        src={`https://www.figma.com/embed?embed_host=share&url=${url}`}
+        allowFullScreen></iframe>
+    </EmbedContainer>
+  );
+};
+
+export default FigmaEmbed;
diff --git a/embed-basic/components/GithubGistEmbed/index.tsx 
b/embed-basic/components/GithubGistEmbed/index.tsx
new file mode 100644
index 0000000..cadb158
--- /dev/null
+++ b/embed-basic/components/GithubGistEmbed/index.tsx
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const GithubGistEmbed = ({ scriptUrl }) => {
+  return (
+    <EmbedContainer>
+      <iframe
+        className="w-100 h-100"
+        src={`data:text/html;charset=utf-8,<head><base target='_blank' 
/></head><body style='margin:0;'><script src='${scriptUrl}'></script></body>`}
+      />
+    </EmbedContainer>
+  );
+};
+
+export default GithubGistEmbed;
diff --git a/embed-basic/components/JSFiddleEmbed/index.tsx 
b/embed-basic/components/JSFiddleEmbed/index.tsx
new file mode 100644
index 0000000..3265776
--- /dev/null
+++ b/embed-basic/components/JSFiddleEmbed/index.tsx
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const JSFiddleEmbed = ({ fiddleId }) => {
+  return (
+    <EmbedContainer>
+      <iframe
+        width="100%"
+        height="100%"
+        src={`https://jsfiddle.net/${fiddleId}/embedded/`}
+        allowFullScreen
+        allowTransparency></iframe>
+    </EmbedContainer>
+  );
+};
+
+export default JSFiddleEmbed;
diff --git a/embed-basic/components/LoomEmbed/index.tsx 
b/embed-basic/components/LoomEmbed/index.tsx
new file mode 100644
index 0000000..00b48df
--- /dev/null
+++ b/embed-basic/components/LoomEmbed/index.tsx
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const LoomEmbed = ({ loomId }) => {
+  return (
+    <EmbedContainer height={380}>
+      <iframe
+        title="Loom"
+        width="100%"
+        height="100%"
+        src={`https://www.loom.com/embed/${loomId}`}
+        frameBorder="0"
+      />
+    </EmbedContainer>
+  );
+};
+
+export default LoomEmbed;
diff --git a/embed-basic/components/TwitterEmbed/index.tsx 
b/embed-basic/components/TwitterEmbed/index.tsx
new file mode 100644
index 0000000..99f865e
--- /dev/null
+++ b/embed-basic/components/TwitterEmbed/index.tsx
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { useRef, useEffect } from 'react';
+import Spinner from 'react-bootstrap/Spinner';
+
+declare global {
+  interface Window {
+    twttr: any;
+  }
+}
+const TwitterEmbed = ({ url, title = '' }) => {
+  const loadingRef = useRef<HTMLDivElement>(null);
+  useEffect(() => {
+    if (!loadingRef.current) {
+      return;
+    }
+    const script = document.createElement('script');
+    script.src = 'https://platform.twitter.com/widgets.js';
+    script.async = true;
+    loadingRef.current.before(script);
+
+    script.onload = () => {
+      if (!window?.twttr) {
+        return;
+      }
+      window.twttr.events.bind('rendered', () => {
+        if (loadingRef.current) {
+          const parentElement = loadingRef.current.parentElement;
+          if (parentElement) {
+            parentElement.style.height = 'auto';
+            parentElement.classList.add('d-flex', 'justify-content-center');
+          }
+          loadingRef.current.remove();
+        }
+      });
+    };
+  }, []);
+  return (
+    <>
+      <blockquote className="twitter-tweet ">
+        <a href={url} target="_blank">
+          {title}
+        </a>
+      </blockquote>
+      <span
+        ref={loadingRef}
+        className="loading position-absolute top-0 left-0 w-100 h-100 z-1 
bg-white d-flex justify-content-center align-items-center">
+        <Spinner animation="border" variant="secondary" />
+      </span>
+    </>
+  );
+};
+
+export default TwitterEmbed;
diff --git a/embed-basic/components/YouTubeEmbed/index.tsx 
b/embed-basic/components/YouTubeEmbed/index.tsx
new file mode 100644
index 0000000..9a5879b
--- /dev/null
+++ b/embed-basic/components/YouTubeEmbed/index.tsx
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import EmbedContainer from '../EmbedContainer';
+
+const YouTubeEmbed = ({ videoId }) => {
+  return (
+    <EmbedContainer height={380}>
+      <iframe
+        width="100%"
+        height="100%"
+        src={`https://www.youtube.com/embed/${videoId}`}
+        title="YouTube video player"
+        allow="accelerometer; autoplay; clipboard-write; encrypted-media; 
gyroscope; picture-in-picture"
+        allowFullScreen
+      />
+    </EmbedContainer>
+  );
+};
+
+export default YouTubeEmbed;
diff --git a/embed-basic/components/index.ts b/embed-basic/components/index.ts
new file mode 100644
index 0000000..c4ad04d
--- /dev/null
+++ b/embed-basic/components/index.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import GithubGistEmbed from './GithubGistEmbed';
+import CodePenEmbed from './CodePenEmbed';
+import YouTubeEmbed from './YouTubeEmbed';
+import JSFiddleEmbed from './JSFiddleEmbed';
+import FigmaEmbed from './FigmaEmbed';
+import ExcalidrawEmbed from './ExcalidrawEmbed';
+import LoomEmbed from './LoomEmbed';
+import DropboxEmbed from './DropboxEmbed';
+import TwitterEmbed from './TwitterEmbed';
+
+export {
+  GithubGistEmbed,
+  CodePenEmbed,
+  YouTubeEmbed,
+  JSFiddleEmbed,
+  FigmaEmbed,
+  ExcalidrawEmbed,
+  LoomEmbed,
+  DropboxEmbed,
+  TwitterEmbed,
+};
diff --git a/embed-basic/hooks.ts b/embed-basic/hooks.tsx
similarity index 74%
rename from embed-basic/hooks.ts
rename to embed-basic/hooks.tsx
index 9380f88..d1a59a3 100644
--- a/embed-basic/hooks.ts
+++ b/embed-basic/hooks.tsx
@@ -17,12 +17,31 @@
  * under the License.
  */
 
-import { useEffect, useState, RefObject } from 'react';
+import {
+  useEffect,
+  useState,
+  RefObject,
+  ReactElement,
+  isValidElement,
+} from 'react';
+import { createRoot } from 'react-dom/client';
+import {
+  GithubGistEmbed,
+  CodePenEmbed,
+  YouTubeEmbed,
+  JSFiddleEmbed,
+  FigmaEmbed,
+  ExcalidrawEmbed,
+  LoomEmbed,
+  DropboxEmbed,
+  TwitterEmbed,
+} from './components';
 
 interface Config {
   platform: string;
   enable: boolean;
 }
+
 const useRenderEmbed = (
   element: HTMLElement | RefObject<HTMLElement> | null,
 ) => {
@@ -37,7 +56,7 @@ const useRenderEmbed = (
         /https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
       ],
       embed: (videoId: string) => {
-        return `<iframe width="100%" height="380" 
src="https://www.youtube.com/embed/${videoId}"; title="YouTube video player" 
frameborder="0" allow="accelerometer; autoplay; clipboard-write; 
encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
+        return <YouTubeEmbed videoId={videoId} />;
       },
     },
     {
@@ -67,7 +86,12 @@ const useRenderEmbed = (
           }
         `;
 
-        return [styleElement, blockquoteElement, scriptElement];
+        return (
+          <TwitterEmbed
+            url={url.replace('x.com', 'twitter.com')}
+            title={title}
+          />
+        );
       },
     },
     {
@@ -77,7 +101,7 @@ const useRenderEmbed = (
         /https:\/\/codepen\.io\/[a-zA-Z0-9_]+\/full\/([a-zA-Z0-9_]+)/,
       ],
       embed: (penId) => {
-        return `<iframe width="100%" height="380" scrolling="no" 
title="CodePen Embed" 
src="https://codepen.io/${penId}/embed/preview/${penId}?height=265&theme-id=0&default-tab=result";
 frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe>`;
+        return <CodePenEmbed penId={penId} />;
       },
     },
     {
@@ -87,7 +111,7 @@ const useRenderEmbed = (
         /https:\/\/jsfiddle\.net\/[a-zA-Z0-9_]+\/([a-zA-Z0-9_]+)\/embed/,
       ],
       embed: (fiddleId: string) => {
-        return `<iframe width="100%" height="380" 
src="https://jsfiddle.net/${fiddleId}/embedded/"; 
allowfullscreen="allowfullscreen" allowpaymentrequest 
frameborder="0"></iframe>`;
+        return <JSFiddleEmbed fiddleId={fiddleId} />;
       },
     },
     {
@@ -98,14 +122,7 @@ const useRenderEmbed = (
       ],
       embed: (_, url) => {
         const scriptUrl = url.indexOf('.js') > -1 ? url : `${url}.js`;
-        console.log(scriptUrl);
-        return `<iframe 
-        width="100%"
-        height="350"    
-        src="data:text/html;charset=utf-8,
-        <head><base target='_blank' /></head>
-        <body style='margin:0;'><script src='${scriptUrl}'></script>
-        </body>">`;
+        return <GithubGistEmbed scriptUrl={scriptUrl} />;
       },
     },
     {
@@ -115,8 +132,7 @@ const useRenderEmbed = (
         /https:\/\/www\.figma\.com\/file\/[a-zA-Z0-9_]+\/([a-zA-Z0-9_]+)/,
       ],
       embed: (_, url) => {
-        return `<iframe style="border: none;" width="100%" height="450
-" src="https://www.figma.com/embed?embed_host=share&url=${url}"; 
allowfullscreen></iframe>`;
+        return <FigmaEmbed url={url} />;
       },
     },
     {
@@ -126,7 +142,7 @@ const useRenderEmbed = (
         /https:\/\/excalidraw\.com\/([a-zA-Z0-9_,-]+)/,
       ],
       embed: (excalidrawId: string) => {
-        return `<iframe width="100%" height="380" 
src="https://excalidraw.com/${excalidrawId}/embed"; frameborder="0"></iframe>`;
+        return <ExcalidrawEmbed excalidrawId={excalidrawId} />;
       },
     },
     {
@@ -136,7 +152,7 @@ const useRenderEmbed = (
         /https:\/\/www\.loom\.com\/share\/([a-zA-Z0-9_]+)/,
       ],
       embed: (loomId: string) => {
-        return `<iframe width="100%" height="380" 
src="https://www.loom.com/embed/${loomId}"; frameborder="0"></iframe>`;
+        return <LoomEmbed loomId={loomId} />;
       },
     },
     {
@@ -145,7 +161,7 @@ const useRenderEmbed = (
         /https:\/\/www\.dropbox\.com\/s\/([a-zA-Z0-9_]+)\/[a-zA-Z0-9_]+/,
       ],
       embed: (dropboxId: string) => {
-        return `<iframe width="100%" height="380" 
src="https://www.dropbox.com/s/${dropboxId}?raw=1"; frameborder="0"></iframe>`;
+        return <DropboxEmbed dropboxId={dropboxId} />;
       },
     },
   ];
@@ -161,7 +177,7 @@ const useRenderEmbed = (
     url: string,
     title: string,
   ): string | HTMLElement | HTMLElement[] => {
-    let html: string | HTMLElement | HTMLElement[] = '';
+    let html: string | HTMLElement | HTMLElement[] | ReactElement = '';
 
     filteredEmbeds.forEach((embed) => {
       if (html) return;
@@ -193,19 +209,11 @@ const useRenderEmbed = (
         return;
       }
       const embed = renderEmbed(url, link?.textContent || '');
-      if (embed) {
+      if (isValidElement(embed)) {
         const parentElement = link.parentElement as HTMLElement;
-        if (typeof embed === 'string') {
-          parentElement.innerHTML = embed;
-        } else if (Array.isArray(embed)) {
-          link.remove();
-          embed.forEach((item) => {
-            parentElement.appendChild(item);
-          });
-        } else {
-          link.innerHTML = '';
-          parentElement.appendChild(embed);
-        }
+        parentElement.classList.add('position-relative');
+        parentElement.style.height = '128px';
+        createRoot(parentElement).render(embed);
       } else {
         link.innerHTML = `
           <div class="border rounded p-3">

Reply via email to