/// import '@blocksuite/blocks'; import type { EmbedBlockModel } from '@blocksuite/blocks'; import { assertExists } from '@blocksuite/global/utils'; import type { Workspace } from '@blocksuite/store'; import { useAtom } from 'jotai'; import type { ReactElement } from 'react'; import { Suspense, useCallback } from 'react'; import { useEffect, useRef, useState } from 'react'; import useSWR from 'swr'; import { imagePreviewModalCloseButtonStyle, imagePreviewModalContainerStyle, imagePreviewModalGoStyle, imagePreviewModalImageStyle, imagePreviewModalStyle, } from './index.css'; import { previewBlockIdAtom } from './index.jotai'; export type ImagePreviewModalProps = { workspace: Workspace; pageId: string; }; const ImagePreviewModalImpl = ( props: ImagePreviewModalProps & { blockId: string; onClose: () => void; } ): ReactElement | null => { const [blockId, setBlockId] = useAtom(previewBlockIdAtom); const [caption, setCaption] = useState(() => { const page = props.workspace.getPage(props.pageId); assertExists(page); const block = page.getBlockById(props.blockId) as EmbedBlockModel | null; assertExists(block); return block.caption; }); useEffect(() => { const page = props.workspace.getPage(props.pageId); assertExists(page); const block = page.getBlockById(props.blockId) as EmbedBlockModel | null; assertExists(block); const disposable = block.propsUpdated.on(() => { setCaption(block.caption); }); return () => { disposable.dispose(); }; }, [props.blockId, props.pageId, props.workspace]); const { data } = useSWR(['workspace', 'embed', props.pageId, props.blockId], { fetcher: ([_, __, pageId, blockId]) => { const page = props.workspace.getPage(pageId); assertExists(page); const block = page.getBlockById(blockId) as EmbedBlockModel | null; assertExists(block); return props.workspace.blobs.get(block.sourceId); }, suspense: true, }); const [prevData, setPrevData] = useState(() => data); const [url, setUrl] = useState(null); const imageRef = useRef(null); if (prevData !== data) { if (url) { URL.revokeObjectURL(url); } setUrl(URL.createObjectURL(data)); setPrevData(data); } else if (!url) { setUrl(URL.createObjectURL(data)); } if (!url) { return null; } return (
{ assertExists(blockId); const workspace = props.workspace; const page = workspace.getPage(props.pageId); assertExists(page); const block = page.getBlockById(blockId); assertExists(block); const prevBlock = page .getPreviousSiblings(block) .findLast( (block): block is EmbedBlockModel => block.flavour === 'affine:embed' ); if (prevBlock) { setBlockId(prevBlock.id); } }} > ❮
{caption}
{ assertExists(blockId); const workspace = props.workspace; const page = workspace.getPage(props.pageId); assertExists(page); const block = page.getBlockById(blockId); assertExists(block); const nextBlock = page .getNextSiblings(block) .find( (block): block is EmbedBlockModel => block.flavour === 'affine:embed' ); if (nextBlock) { setBlockId(nextBlock.id); } }} > ❯
); }; export const ImagePreviewModal = ( props: ImagePreviewModalProps ): ReactElement | null => { const [blockId, setBlockId] = useAtom(previewBlockIdAtom); const handleKeyUp = useCallback( (event: KeyboardEvent) => { if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); setBlockId(null); return; } if (!blockId) { return; } const workspace = props.workspace; const page = workspace.getPage(props.pageId); assertExists(page); const block = page.getBlockById(blockId); assertExists(block); if (event.key === 'ArrowLeft') { const prevBlock = page .getPreviousSiblings(block) .findLast( (block): block is EmbedBlockModel => block.flavour === 'affine:embed' ); if (prevBlock) { setBlockId(prevBlock.id); } } else if (event.key === 'ArrowRight') { const nextBlock = page .getNextSiblings(block) .find( (block): block is EmbedBlockModel => block.flavour === 'affine:embed' ); if (nextBlock) { setBlockId(nextBlock.id); } } else { return; } event.preventDefault(); event.stopPropagation(); }, [blockId, setBlockId, props.workspace, props.pageId] ); useEffect(() => { document.addEventListener('keyup', handleKeyUp); return () => { document.removeEventListener('keyup', handleKeyUp); }; }, [handleKeyUp]); if (!blockId) { return null; } return ( }> setBlockId(null)} /> ); };