fix(editor): improve viewport of surface ref block (#12014)

Close [BS-3339](https://linear.app/affine-design/issue/BS-3339/一个frame插入到page之后大的离谱)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Improvements**
  - Enhanced the accuracy and responsiveness of viewport and reference content rendering for surface references.
  - Adjusted padding for a more consistent viewing experience.
  - Improved handling of referenced elements to ensure smoother updates and display.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
L-Sun
2025-04-29 03:39:01 +00:00
parent e96fcf0c35
commit 8b402dd49a

View File

@@ -1,4 +1,4 @@
import { type FrameBlockComponent } from '@blocksuite/affine-block-frame'; import { FrameBlockComponent } from '@blocksuite/affine-block-frame';
import { import {
EdgelessCRUDIdentifier, EdgelessCRUDIdentifier,
getSurfaceBlock, getSurfaceBlock,
@@ -24,12 +24,7 @@ import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { requestConnectedFrame } from '@blocksuite/affine-shared/utils'; import { requestConnectedFrame } from '@blocksuite/affine-shared/utils';
import { DisposableGroup } from '@blocksuite/global/disposable'; import { DisposableGroup } from '@blocksuite/global/disposable';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { import { Bound, type SerializedXYWH } from '@blocksuite/global/gfx';
Bound,
deserializeXYWH,
type SerializedXYWH,
} from '@blocksuite/global/gfx';
import { assertType } from '@blocksuite/global/utils';
import { import {
BlockComponent, BlockComponent,
BlockSelection, BlockSelection,
@@ -127,6 +122,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
private _referencedModel: GfxModel | null = null; private _referencedModel: GfxModel | null = null;
// since the xywh of edgeless element is not a signal, we need to use a signal to store the xywh
private readonly _referenceXYWH$ = signal<SerializedXYWH | null>(null); private readonly _referenceXYWH$ = signal<SerializedXYWH | null>(null);
private get _shouldRender() { private get _shouldRender() {
@@ -263,6 +259,8 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
} }
private _initViewport() { private _initViewport() {
this._referenceXYWH$.value = this.referenceModel?.xywh ?? null;
const refreshViewport = () => { const refreshViewport = () => {
if (!this._referenceXYWH$.value) return; if (!this._referenceXYWH$.value) return;
const previewEditorHost = this.previewEditor; const previewEditorHost = this.previewEditor;
@@ -270,14 +268,12 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
const gfx = previewEditorHost.std.get(GfxControllerIdentifier); const gfx = previewEditorHost.std.get(GfxControllerIdentifier);
const viewport = gfx.viewport; const viewport = gfx.viewport;
let bound = Bound.deserialize(this._referenceXYWH$.value); viewport.setViewportByBound(
const w = Math.max(this.getBoundingClientRect().width, bound.w); Bound.deserialize(this._referenceXYWH$.value),
const aspectRatio = bound.w / bound.h; this.referenceModel instanceof FrameBlockModel
const h = w / aspectRatio; ? undefined
: [20, 20, 20, 20]
bound = Bound.fromCenter(bound.center, w, h); );
viewport.setViewportByBound(bound);
}; };
this.disposables.add(effect(refreshViewport)); this.disposables.add(effect(refreshViewport));
@@ -304,28 +300,15 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
referenceXYWH$.value = referenceElement.xywh; referenceXYWH$.value = referenceElement.xywh;
const { _disposable } = this; const { _disposable } = this;
refreshViewport();
_disposable.add(viewport.sizeUpdated.subscribe(refreshViewport)); _disposable.add(viewport.sizeUpdated.subscribe(refreshViewport));
if (referenceElement instanceof FrameBlockModel) { if (referenceElement instanceof GfxBlockElementModel) {
_disposable.add( _disposable.add(
referenceElement.xywh$.subscribe(xywh => { referenceElement.xywh$.subscribe(xywh => {
referenceXYWH$.value = xywh; referenceXYWH$.value = xywh;
}) })
); );
const subscription = this.std.view.viewUpdated.subscribe(
({ id, type, method, view }) => {
if (
id === referenceElement.id &&
type === 'block' &&
method === 'add'
) {
assertType<FrameBlockComponent>(view);
view.showBorder = false;
subscription.unsubscribe();
}
}
);
_disposable.add(subscription);
} else if (referenceElement instanceof GfxPrimitiveElementModel) { } else if (referenceElement instanceof GfxPrimitiveElementModel) {
_disposable.add( _disposable.add(
surface.elementUpdated.subscribe(({ id, oldValues }) => { surface.elementUpdated.subscribe(({ id, oldValues }) => {
@@ -338,6 +321,21 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
}) })
); );
} }
const subscription = this.std.view.viewUpdated.subscribe(
({ id, type, method, view }) => {
if (
id === referenceElement.id &&
type === 'block' &&
method === 'add' &&
view instanceof FrameBlockComponent
) {
view.showBorder = false;
subscription.unsubscribe();
}
}
);
_disposable.add(subscription);
} }
override unmounted() { override unmounted() {
@@ -371,15 +369,17 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
this._disposables.add(dispose); this._disposables.add(dispose);
} }
private _renderRefContent(referencedModel: GfxModel) { private _renderRefContent() {
const [, , w, h] = deserializeXYWH(referencedModel.xywh); if (!this._referenceXYWH$.value) return nothing;
const { w, h } = Bound.deserialize(this._referenceXYWH$.value);
const aspectRatio = h !== 0 ? w / h : 1;
const _previewSpec = this._previewSpec.concat(this._runtimePreviewExt); const _previewSpec = this._previewSpec.concat(this._runtimePreviewExt);
return html`<div class="ref-content"> return html`<div class="ref-content">
<div <div
class="ref-viewport" class="ref-viewport"
style=${styleMap({ style=${styleMap({
aspectRatio: `${w} / ${h}`, aspectRatio: `${aspectRatio}`,
})} })}
> >
${guard(this._previewDoc, () => { ${guard(this._previewDoc, () => {
@@ -424,9 +424,9 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
if (!this._shouldRender) return; if (!this._shouldRender) return;
this._initReferencedModel();
this._initHotkey(); this._initHotkey();
this._initViewport(); this._initViewport();
this._initReferencedModel();
} }
override firstUpdated() { override firstUpdated() {
@@ -445,7 +445,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
.referenceModel=${_referencedModel} .referenceModel=${_referencedModel}
.refFlavour=${model.props.refFlavour$.value} .refFlavour=${model.props.refFlavour$.value}
></surface-ref-placeholder>` ></surface-ref-placeholder>`
: this._renderRefContent(_referencedModel); : this._renderRefContent();
const edgelessTheme = this.std.get(ThemeProvider).edgeless$.value; const edgelessTheme = this.std.get(ThemeProvider).edgeless$.value;
return html` return html`
@@ -471,7 +471,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
const viewport = { const viewport = {
xywh: this._referenceXYWH$.value, xywh: this._referenceXYWH$.value,
padding: [60, 20, 20, 20] as [number, number, number, number], padding: [20, 20, 20, 20] as [number, number, number, number],
}; };
this.std.get(EditPropsStore).setStorage('viewport', viewport); this.std.get(EditPropsStore).setStorage('viewport', viewport);