diff --git a/src/components/Media/Iframe/Iframe.scss b/src/components/Media/Iframe/Iframe.scss index 9ced1dc89..548c819cb 100644 --- a/src/components/Media/Iframe/Iframe.scss +++ b/src/components/Media/Iframe/Iframe.scss @@ -17,9 +17,4 @@ $block: '.#{$ns}media-component-iframe'; #{$block}__iframe { border-radius: 0; } - - &__item { - width: 100%; - height: 100%; - } } diff --git a/src/components/Media/Iframe/Iframe.tsx b/src/components/Media/Iframe/Iframe.tsx index 417511916..e4c819f1c 100644 --- a/src/components/Media/Iframe/Iframe.tsx +++ b/src/components/Media/Iframe/Iframe.tsx @@ -1,4 +1,6 @@ -import React from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; + +import {v4 as uuidv4} from 'uuid'; import {MediaComponentIframeProps} from '../../../models'; import {block} from '../../../utils'; @@ -11,21 +13,91 @@ const b = block('media-component-iframe'); const Iframe = (props: MediaComponentIframeProps) => { const {iframe, margins = true} = props; - const {height = 400, src, width, name, title} = iframe; + const {height = 400, src, width = '100%', name, title, justifyContent = 'center'} = iframe; + + const formContainerRef = useRef(null); + const iframeRef = useRef(); + const {current: iframeId} = useRef(uuidv4()); + + const updateIframe = useCallback( + (container: HTMLDivElement) => { + if (iframeRef.current) { + iframeRef.current.src = src; + } else { + const iframeWidth = typeof width === 'number' ? `${width}px` : width; + let iframeHeight: string | number | undefined = + typeof height === 'number' ? `${height}px` : height; + + if (height === 'auto') { + iframeHeight = undefined; + } + + iframeRef.current = document.createElement('iframe'); + iframeRef.current.src = src; + iframeRef.current.id = iframeId; + iframeRef.current.name = name || iframeId; + iframeRef.current.setAttribute('loading', 'lazy'); + iframeRef.current.setAttribute('title', title || i18n('iframe-title')); + iframeRef.current.frameBorder = '0'; + iframeRef.current.scrolling = 'no'; + iframeRef.current.width = iframeWidth; + iframeRef.current.style.width = iframeWidth; + if (iframeHeight) { + iframeRef.current.style.height = iframeHeight; + } + + container.appendChild(iframeRef.current); + } + }, + [src, width, iframeId, name, title, height], + ); + + const handleMessage = useCallback( + ({data}: MessageEvent) => { + if (height !== 'auto' && typeof height === 'number' && iframeRef.current) { + iframeRef.current.height = `${height}px`; + return; + } + + try { + const parsed = JSON.parse(data); + const iframeHeight = parsed['iframe-height']; + const {message, name: iframeName} = parsed; + if (iframeName !== name && iframeName !== iframeId) { + return; + } + + if (iframeRef.current && iframeHeight && !message) { + iframeRef.current.height = `${iframeHeight}px`; + } + } catch (error) { + return; + } + }, + [height, iframeId, name], + ); + + const addIframe = useCallback(() => { + const container = formContainerRef.current; + + if (container) { + updateIframe(container); + window.addEventListener('message', handleMessage, {passive: true}); + } + }, [updateIframe, handleMessage]); + + useEffect(() => { + addIframe(); + + return () => window.removeEventListener('message', handleMessage); + }, [addIframe, handleMessage]); return iframe ? ( -
-