refactor(core): improve scroll anchoring logic (#8269)

Upstreams: https://github.com/toeverything/blocksuite/pull/8378
This commit is contained in:
fundon
2024-09-19 02:58:11 +00:00
parent 03ac9bc4a1
commit 6921c3073c
4 changed files with 39 additions and 110 deletions

View File

@@ -180,12 +180,12 @@ export class Editor extends Entity {
(a, b) => a?.id === b?.id && a?.refreshKey === b?.refreshKey
)
.subscribe(params => {
if (params?.id) {
const std = editorContainer.host?.std;
if (std) {
scrollAnchoring(std, this.mode$.value, params.id);
}
}
if (!params?.id) return;
const std = editorContainer.host?.std;
if (!std) return;
scrollAnchoring(std, this.mode$.value, params.id);
});
unsubs.push(subscription.unsubscribe.bind(subscription));

View File

@@ -1,115 +1,43 @@
import { notify } from '@affine/component';
import { I18n } from '@affine/i18n';
import type { BlockStdScope, SelectionManager } from '@blocksuite/block-std';
import type {
DocMode,
EdgelessRootService,
PageRootService,
} from '@blocksuite/blocks';
import { Bound, deserializeXYWH } from '@blocksuite/global/utils';
function scrollAnchoringInEdgelessMode(
service: EdgelessRootService,
id: string
) {
requestAnimationFrame(() => {
let bounds: Bound | null = null;
let pageSelection: SelectionManager | null = null;
const blockComponent = service.std.view.getBlock(id);
const parentComponent = blockComponent?.parentComponent;
if (parentComponent && parentComponent.flavour === 'affine:note') {
pageSelection = parentComponent.std.selection;
if (!pageSelection) return;
const { left: x, width: w } = parentComponent.getBoundingClientRect();
const { top: y, height: h } = blockComponent.getBoundingClientRect();
const coord = service.viewport.toModelCoordFromClientCoord([x, y]);
bounds = new Bound(
coord[0],
coord[1],
w / service.viewport.zoom,
h / service.viewport.zoom
);
} else {
if (!service.getElementById) return;
const model = service.getElementById(id);
if (!model) return;
bounds = Bound.fromXYWH(deserializeXYWH(model.xywh));
}
if (!bounds) {
notify.error({ title: I18n['Block not found']() });
return;
}
const { zoom, centerX, centerY } = service.getFitToScreenData(
[20, 20, 100, 20],
[bounds]
);
service.viewport.setCenter(centerX, centerY);
service.viewport.setZoom(zoom);
if (pageSelection) {
pageSelection.setGroup('note', [
pageSelection.create('block', {
blockId: id,
}),
]);
} else {
service.selection.set({
elements: [id],
editing: false,
});
}
// const surfaceComponent = service.std.view.getBlock(service.surface.id);
// if (!surfaceComponent) return;
// (surfaceComponent as SurfaceBlockComponent).refresh();
// TODO(@fundon): toolbar should be hidden
});
}
function scrollAnchoringInPageMode(service: PageRootService, id: string) {
const blockComponent = service.std.view.getBlock(id);
if (!blockComponent) {
notify.error({ title: I18n['Block not found']() });
return;
}
blockComponent.scrollIntoView({
behavior: 'instant',
block: 'center',
});
const selection = service.std.selection;
if (!selection) return;
selection.setGroup('note', [
selection.create('block', {
blockId: id,
}),
]);
// TODO(@fundon): toolbar should be hidden
}
import type { BlockStdScope } from '@blocksuite/block-std';
import {
GfxControllerIdentifier,
type GfxModel,
} from '@blocksuite/block-std/gfx';
import type { DocMode } from '@blocksuite/blocks';
// TODO(@fundon): it should be a command
export function scrollAnchoring(std: BlockStdScope, mode: DocMode, id: string) {
if (mode === 'edgeless') {
const service = std.getService<EdgelessRootService>('affine:page');
if (!service) return;
let key = 'blockIds';
let exists = false;
scrollAnchoringInEdgelessMode(service, id);
if (mode === 'page') {
exists = std.doc.hasBlock(id);
} else {
const controller = std.getOptional(GfxControllerIdentifier);
if (!controller) return;
exists = !!controller.getElementById<GfxModel>(id)?.xywh;
if (controller.surface?.hasElementById(id)) {
key = 'elementIds';
}
}
if (!exists) {
notify.error({
title: I18n['Block not found'](),
message: I18n['Block not found description'](),
});
return;
}
const service = std.getService<PageRootService>('affine:page');
if (!service) return;
const selection = std.selection;
scrollAnchoringInPageMode(service, id);
selection.setGroup('scene', [
selection.create('highlight', {
mode,
[key]: [id],
}),
]);
}