mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
Merge pull request #31 from toeverything/bugfix/iframe
fix iframe will take away the focus
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user