mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-02 09:59:55 +08:00
feat(editor): support embed iframe block in edgeless (#10830)
To close: [BS-2665](https://linear.app/affine-design/issue/BS-2665/iframe-embed-block-edgeless-mode-支持) [BS-2666](https://linear.app/affine-design/issue/BS-2666/iframe-embed-block-edgeless-toolbar) [BS-2667](https://linear.app/affine-design/issue/BS-2667/iframe-embed-block-edgeless-mode-拖拽调整支持) [BS-2789](https://linear.app/affine-design/issue/BS-2789/iframe-embed-block-edgeless-block-component)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export * from './insert-embed-iframe';
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
EdgelessCRUDIdentifier,
|
||||
SurfaceBlockComponent,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
BlockSelection,
|
||||
type Command,
|
||||
SurfaceSelection,
|
||||
TextSelection,
|
||||
} from '@blocksuite/block-std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||
import { Bound, Vec } from '@blocksuite/global/gfx';
|
||||
|
||||
import {
|
||||
EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE,
|
||||
EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE,
|
||||
} from '../consts';
|
||||
import { EmbedIframeService } from '../extension/embed-iframe-service';
|
||||
|
||||
export const insertEmbedIframeCommand: Command<
|
||||
{ url: string },
|
||||
{ blockId: string; flavour: string }
|
||||
> = (ctx, next) => {
|
||||
const { url, std } = ctx;
|
||||
const embedIframeService = std.get(EmbedIframeService);
|
||||
if (!embedIframeService || !embedIframeService.canEmbed(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = embedIframeService.getConfig(url);
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { host } = std;
|
||||
const selectionManager = host.selection;
|
||||
|
||||
let selectedBlockId: string | undefined;
|
||||
const textSelection = selectionManager.find(TextSelection);
|
||||
const blockSelection = selectionManager.find(BlockSelection);
|
||||
const surfaceSelection = selectionManager.find(SurfaceSelection);
|
||||
if (textSelection) {
|
||||
selectedBlockId = textSelection.blockId;
|
||||
} else if (blockSelection) {
|
||||
selectedBlockId = blockSelection.blockId;
|
||||
} else if (surfaceSelection && surfaceSelection.editing) {
|
||||
selectedBlockId = surfaceSelection.blockId;
|
||||
}
|
||||
|
||||
const flavour = 'affine:embed-iframe';
|
||||
const props: Record<string, unknown> = { url };
|
||||
// When there is a selected block, it means that the selection is in note or edgeless text
|
||||
// we should insert the embed iframe block after the selected block and only need the url prop
|
||||
let newBlockId: string | undefined;
|
||||
if (selectedBlockId) {
|
||||
const block = host.view.getBlock(selectedBlockId);
|
||||
if (!block) return;
|
||||
const parent = host.doc.getParent(block.model);
|
||||
if (!parent) return;
|
||||
const index = parent.children.indexOf(block.model);
|
||||
newBlockId = host.doc.addBlock(flavour, props, parent, index + 1);
|
||||
} else {
|
||||
// When there is no selected block and in edgeless mode
|
||||
// We should insert the embed iframe block to surface
|
||||
// It means that not only the url prop but also the xywh prop is needed
|
||||
const rootId = std.store.root?.id;
|
||||
if (!rootId) return;
|
||||
const edgelessRoot = std.view.getBlock(rootId);
|
||||
if (!edgelessRoot) return;
|
||||
|
||||
const gfx = std.get(GfxControllerIdentifier);
|
||||
const crud = std.get(EdgelessCRUDIdentifier);
|
||||
|
||||
gfx.viewport.smoothZoom(1);
|
||||
const surfaceBlock = gfx.surfaceComponent;
|
||||
if (!(surfaceBlock instanceof SurfaceBlockComponent)) return;
|
||||
|
||||
const options = config.options;
|
||||
const { widthInSurface, heightInSurface } = options ?? {};
|
||||
const width = widthInSurface ?? EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE;
|
||||
const height = heightInSurface ?? EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE;
|
||||
const center = Vec.toVec(surfaceBlock.renderer.viewport.center);
|
||||
const xywh = Bound.fromCenter(center, width, height).serialize();
|
||||
newBlockId = crud.addBlock(
|
||||
flavour,
|
||||
{
|
||||
...props,
|
||||
xywh,
|
||||
},
|
||||
surfaceBlock.model
|
||||
);
|
||||
|
||||
gfx.selection.set({
|
||||
elements: [newBlockId],
|
||||
editing: false,
|
||||
});
|
||||
|
||||
gfx.tool.setTool(
|
||||
// @ts-expect-error FIXME: resolve after gfx tool refactor
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
if (!newBlockId) {
|
||||
return;
|
||||
}
|
||||
|
||||
next({ blockId: newBlockId, flavour });
|
||||
};
|
||||
Reference in New Issue
Block a user