fix(editor): incorrect edgeless viewport in peek view (#11040)

### What Changes
- Fixed incorrect edgeless viewport display in peek view
  - Moved page block viewport fit animation logic from `EdgelessRootBlockComponent` to note config extension
  - Disabled page block viewport fit animation in peek view, using default `fitToScreen` instead
  - @doodlewind Fixed viewport resizing issues by adding a immediate update mechanism to ensure proper rendering during peek view operations.  The setViewportByBound is only called once during peek view initialization, so there are barely perf overhead.
- Updated related test cases
  - Refactored peek view test cases to make them clearer and more reliable
  - Added new test helper function `getViewportBound` for getting viewport boundary information
This commit is contained in:
L-Sun
2025-03-26 09:29:04 +00:00
parent a4b4029201
commit c23b8f604b
9 changed files with 246 additions and 145 deletions

View File

@@ -19,6 +19,7 @@ import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { JournalService } from '@affine/core/modules/journal';
import { toURLSearchParams } from '@affine/core/modules/navigation';
import { useInsidePeekView } from '@affine/core/modules/peek-view';
import { PeekViewService } from '@affine/core/modules/peek-view/services/peek-view';
import { MemberSearchService } from '@affine/core/modules/permissions';
import { WorkspaceService } from '@affine/core/modules/workspace';
@@ -147,6 +148,8 @@ const usePatchSpecs = (mode: DocMode) => {
const enableAI = useEnableAI();
const insidePeekView = useInsidePeekView();
const enableTurboRenderer = useLiveData(
featureFlagService.flags.enable_turbo_renderer.$
);
@@ -165,7 +168,7 @@ const usePatchSpecs = (mode: DocMode) => {
builder.extend(
[
patchReferenceRenderer(reactToLit, referenceRenderer),
patchForEdgelessNoteConfig(framework, reactToLit),
patchForEdgelessNoteConfig(framework, reactToLit, insidePeekView),
patchNotificationService(confirmModal),
patchPeekViewService(peekViewService),
patchOpenDocExtension(),
@@ -207,6 +210,7 @@ const usePatchSpecs = (mode: DocMode) => {
enableAI,
reactToLit,
referenceRenderer,
insidePeekView,
confirmModal,
peekViewService,
docService,

View File

@@ -1,6 +1,13 @@
import type { ElementOrFactory } from '@affine/component';
import { JournalService } from '@affine/core/modules/journal';
import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx';
import { NoteConfigExtension } from '@blocksuite/affine/blocks/note';
import { EDGELESS_BLOCK_CHILD_PADDING } from '@blocksuite/affine/blocks/root';
import { Bound, Vec } from '@blocksuite/affine/global/gfx';
import {
DocModeProvider,
EditPropsStore,
} from '@blocksuite/affine/shared/services';
import type { FrameworkProvider } from '@toeverything/infra';
import { html, type TemplateResult } from 'lit';
@@ -9,7 +16,8 @@ import { EdgelessNoteHeader } from './edgeless-note-header';
export function patchForEdgelessNoteConfig(
framework: FrameworkProvider,
reactToLit: (element: ElementOrFactory) => TemplateResult
reactToLit: (element: ElementOrFactory) => TemplateResult,
insidePeekView: boolean
) {
return NoteConfigExtension({
edgelessNoteHeader: ({ note }) =>
@@ -23,5 +31,69 @@ export function patchForEdgelessNoteConfig(
return html`<doc-title .doc=${note.doc}></doc-title>`;
}
},
pageBlockViewportFitAnimation: insidePeekView
? undefined
: ({ std, note }) => {
const storedViewport = std.get(EditPropsStore).getStorage('viewport');
// if there is a stored viewport, don't run the animation
// in other word, this doc has been opened before
if (storedViewport) return false;
if (!std.store.root) return false;
const rootView = std.view.getBlock(std.store.root.id);
if (!rootView) return false;
const gfx = std.get(GfxControllerIdentifier);
const primaryMode = std
.get(DocModeProvider)
.getPrimaryMode(std.store.id);
if (primaryMode !== 'page' || !note || note.props.edgeless.collapse) {
return false;
}
const leftPadding = parseInt(
window
.getComputedStyle(rootView)
.getPropertyValue('--affine-editor-side-padding')
.replace('px', '')
);
if (isNaN(leftPadding)) {
return false;
}
let editorWidth = parseInt(
window
.getComputedStyle(rootView)
.getPropertyValue('--affine-editor-width')
.replace('px', '')
);
if (isNaN(editorWidth)) {
return false;
}
const containerWidth = rootView.getBoundingClientRect().width;
const leftMargin =
containerWidth > editorWidth
? (containerWidth - editorWidth) / 2
: 0;
const pageTitleAnchor = gfx.viewport.toModelCoord(
leftPadding + leftMargin,
0
);
const noteBound = Bound.deserialize(note.xywh);
const edgelessTitleAnchor = Vec.add(noteBound.tl, [
EDGELESS_BLOCK_CHILD_PADDING,
12,
]);
const center = Vec.sub(edgelessTitleAnchor, pageTitleAnchor);
gfx.viewport.setCenter(center[0], center[1], true);
gfx.viewport.smoothZoom(0.65, undefined, 15);
return true;
},
});
}

View File

@@ -58,7 +58,8 @@ function fitViewport(
viewport.setViewportByBound(
Bound.deserialize(newViewport.xywh),
newViewport.padding,
false
false,
true
);
} else {
gfx.fitToScreen({