Merge pull request #31 from toeverything/bugfix/iframe

fix iframe will take away the focus
This commit is contained in:
DiamondThree
2022-08-04 22:03:27 +08:00
committed by GitHub
3 changed files with 169 additions and 36 deletions

View File

@@ -1,6 +1,18 @@
import type { AsyncBlock } from '@toeverything/components/editor-core'; import {
AsyncBlock,
useCurrentView,
useLazyIframe,
} from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui'; import { styled } from '@toeverything/components/ui';
import type { FC } from 'react'; import {
FC,
ReactElement,
ReactNode,
useEffect,
useRef,
useState,
} from 'react';
import { SCENE_CONFIG } from '../../blocks/group/config';
import { BlockPreview } from './BlockView'; import { BlockPreview } from './BlockView';
import { formatUrl } from './format-url'; import { formatUrl } from './format-url';
@@ -15,7 +27,18 @@ export interface Props {
} }
const getHost = (url: string) => new URL(url).host; const getHost = (url: string) => new URL(url).host;
const MouseMaskContainer = styled('div')({
position: 'absolute',
zIndex: 1,
top: '0px',
left: '0px',
right: '0px',
bottom: '0px',
backgroundColor: 'transparent',
'&:hover': {
pointerEvents: 'none',
},
});
const LinkContainer = styled('div')<{ const LinkContainer = styled('div')<{
isSelected: boolean; isSelected: boolean;
}>(({ theme, isSelected }) => { }>(({ theme, isSelected }) => {
@@ -38,12 +61,28 @@ const LinkContainer = styled('div')<{
}, },
}; };
}); });
const _getLinkStyle = (scene: string) => {
switch (scene) {
case SCENE_CONFIG.PAGE:
return {
width: '420px',
height: '198px',
};
default:
return {
width: '252px',
height: '126px',
};
}
};
const SourceViewContainer = styled('div')<{ const SourceViewContainer = styled('div')<{
isSelected: boolean; isSelected: boolean;
}>(({ theme, isSelected }) => { scene: string;
}>(({ theme, isSelected, scene }) => {
return { return {
..._getLinkStyle(scene),
overflow: 'hidden', overflow: 'hidden',
position: 'relative',
borderRadius: theme.affine.shape.borderRadius, borderRadius: theme.affine.shape.borderRadius,
background: isSelected ? 'rgba(152, 172, 189, 0.1)' : 'transparent', background: isSelected ? 'rgba(152, 172, 189, 0.1)' : 'transparent',
padding: '8px', padding: '8px',
@@ -52,32 +91,96 @@ const SourceViewContainer = styled('div')<{
height: '100%', height: '100%',
border: '1px solid #EAEEF2', border: '1px solid #EAEEF2',
borderRadius: theme.affine.shape.borderRadius, borderRadius: theme.affine.shape.borderRadius,
userSelect: 'none',
}, },
}; };
}); });
const LazyIframe = ({
src,
delay = 3000,
fallback,
}: {
src: string;
delay?: number;
fallback?: ReactNode;
}) => {
const [show, setShow] = useState(false);
const timer = useRef<number>();
useEffect(() => {
// Hide iframe when the src changed
setShow(false);
}, [src]);
const onLoad = () => {
clearTimeout(timer.current);
timer.current = window.setTimeout(() => {
// Prevent iframe scrolling parent container
// Remove the delay after the issue is resolved
// See W3C https://github.com/w3c/csswg-drafts/issues/7134
// See https://forum.figma.com/t/prevent-figmas-embed-code-from-automatically-scrolling-to-it-on-page-load/26029/6
setShow(true);
}, delay);
};
return (
<>
<div
onMouseDown={e => {
e.preventDefault();
e.stopPropagation();
}}
style={{ display: show ? 'block' : 'none', height: '100%' }}
>
<iframe src={src} onLoad={onLoad} />
</div>
{!show && fallback}
</>
);
};
const Loading = styled('div')(() => {
return {
width: '100%',
height: '100%',
display: 'flex',
lineHeight: '100%',
alignItems: 'center',
justifyContent: 'center',
border: '1px solid #EAEEF2',
};
});
const LoadingContiner = () => {
return <Loading>loading...</Loading>;
};
export const SourceView: FC<Props> = props => { export const SourceView: FC<Props> = props => {
const { link, isSelected, block, editorElement } = props; const { link, isSelected, block, editorElement } = props;
const src = formatUrl(link); const src = formatUrl(link);
const openTabOnBrowser = () => { // let iframeShow = useLazyIframe(src, 3000, iframeContainer);
window.open(link, '_blank'); const [currentView] = useCurrentView();
}; const { type } = currentView;
if (src?.startsWith('http')) { if (src?.startsWith('http')) {
return ( return (
<LinkContainer <div style={{ display: 'flex' }}>
isSelected={isSelected} <SourceViewContainer isSelected={isSelected} scene={type}>
onMouseDown={e => e.preventDefault()} <MouseMaskContainer />
onClick={openTabOnBrowser}
> <LazyIframe
<p>{getHost(src)}</p> src={src}
<p>{src}</p> fallback={LoadingContiner()}
</LinkContainer> ></LazyIframe>
</SourceViewContainer>
</div>
); );
} else if (src?.startsWith('affine')) { } else if (src?.startsWith('affine')) {
return ( return (
<SourceViewContainer <SourceViewContainer
isSelected={isSelected} isSelected={isSelected}
style={{ padding: '0' }} style={{ padding: '0' }}
scene={type}
> >
<BlockPreview <BlockPreview
block={block} block={block}

View File

@@ -1,5 +1,5 @@
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { useCallback } from 'react'; import { MutableRefObject, useCallback, useEffect, useState } from 'react';
import { useRecastBlock } from './Context'; import { useRecastBlock } from './Context';
import { import {
KanbanView, KanbanView,
@@ -50,7 +50,33 @@ export const useCurrentView = () => {
); );
return [currentView, setCurrentView] as const; return [currentView, setCurrentView] as const;
}; };
export const useLazyIframe = (
link: string,
timers: number,
container: MutableRefObject<HTMLElement>
) => {
const [iframeShow, setIframeShow] = useState(false);
useEffect(() => {
const iframe = document.createElement('iframe');
iframe.src = link;
iframe.onload = () => {
setTimeout(() => {
// Prevent iframe from scrolling parent container
// TODO W3C https://github.com/w3c/csswg-drafts/issues/7134
// https://forum.figma.com/t/prevent-figmas-embed-code-from-automatically-scrolling-to-it-on-page-load/26029/6
setIframeShow(true);
}, timers);
};
if (container?.current) {
container.current.appendChild(iframe);
}
return () => {
iframe.remove();
};
}, [link, container]);
return iframeShow;
};
export const useRecastView = () => { export const useRecastView = () => {
const recastBlock = useRecastBlock(); const recastBlock = useRecastBlock();
const recastViews = const recastViews =

View File

@@ -242,25 +242,29 @@ export const CommandMenu = ({ editor, hooks, style }: CommandMenuProps) => {
onKeyUpCapture={handleKeyup} onKeyUpCapture={handleKeyup}
ref={commandMenuContentRef} ref={commandMenuContentRef}
> >
<MuiClickAwayListener onClickAway={handleClickAway}> {show ? (
<div> <MuiClickAwayListener onClickAway={handleClickAway}>
<CommandMenuContainer <div>
editor={editor} <CommandMenuContainer
hooks={hooks} editor={editor}
style={{ hooks={hooks}
...commandMenuPosition, style={{
...style, ...commandMenuPosition,
}} ...style,
isShow={show} }}
blockId={blockId} isShow={show}
onSelected={handleSelected} blockId={blockId}
onclose={handleClose} onSelected={handleSelected}
searchBlocks={searchBlocks} onclose={handleClose}
types={types} searchBlocks={searchBlocks}
categories={categories} types={types}
/> categories={categories}
</div> />
</MuiClickAwayListener> </div>
</MuiClickAwayListener>
) : (
<></>
)}
</div> </div>
); );
}; };