mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-11 07:06:28 +08:00
fix(editor): sync gfx block transform update with RAF to prevent stale transform (#11322)
Close [BS-2866](https://linear.app/affine-design/issue/BS-2866/presentation-mode中的note消失) ## Problem When using RequestAnimationFrame (RAF) for GFX block updates, there was a timing issue where the transform update would lag behind the RAF callback, causing the block to display with the previous frame's transform state. ## Solution 1. Refactored the block state management to use signals for better reactivity 2. Moved block visibility state management from `viewport-element.ts` to `gfx-block-component.ts` 3. Added `transformState$` signal to track block state 4. Synchronized transform updates with RAF using `effect` to ensure updates happen in the correct frame 5. Added test case to verify note visibility in presentation mode
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { Bound } from '@blocksuite/global/gfx';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { computed, effect, signal } from '@preact/signals-core';
|
||||
import { nothing } from 'lit';
|
||||
|
||||
import type { BlockService } from '../../extension/index.js';
|
||||
@@ -23,7 +23,7 @@ export function isGfxBlockComponent(
|
||||
export const GfxElementSymbol = Symbol('GfxElement');
|
||||
|
||||
function updateTransform(element: GfxBlockComponent) {
|
||||
if (element.dataset.blockState === 'idle') return;
|
||||
if (element.transformState$.value === 'idle') return;
|
||||
|
||||
const { viewport } = element.gfx;
|
||||
element.dataset.viewportState = viewport.serializeRecord();
|
||||
@@ -31,6 +31,20 @@ function updateTransform(element: GfxBlockComponent) {
|
||||
element.style.transform = element.getCSSTransform();
|
||||
}
|
||||
|
||||
function updateBlockVisibility(view: GfxBlockComponent) {
|
||||
if (view.transformState$.value === 'active') {
|
||||
view.style.visibility = 'visible';
|
||||
view.style.pointerEvents = 'auto';
|
||||
view.classList.remove('block-idle');
|
||||
view.classList.add('block-active');
|
||||
} else {
|
||||
view.style.visibility = 'hidden';
|
||||
view.style.pointerEvents = 'none';
|
||||
view.classList.remove('block-active');
|
||||
view.classList.add('block-idle');
|
||||
}
|
||||
}
|
||||
|
||||
function handleGfxConnection(instance: GfxBlockComponent) {
|
||||
instance.style.position = 'absolute';
|
||||
|
||||
@@ -48,7 +62,12 @@ function handleGfxConnection(instance: GfxBlockComponent) {
|
||||
})
|
||||
);
|
||||
|
||||
updateTransform(instance);
|
||||
instance.disposables.add(
|
||||
effect(() => {
|
||||
updateBlockVisibility(instance);
|
||||
updateTransform(instance);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export abstract class GfxBlockComponent<
|
||||
@@ -61,6 +80,8 @@ export abstract class GfxBlockComponent<
|
||||
{
|
||||
[GfxElementSymbol] = true;
|
||||
|
||||
readonly transformState$ = signal<'idle' | 'active'>('active');
|
||||
|
||||
get gfx() {
|
||||
return this.std.get(GfxControllerIdentifier);
|
||||
}
|
||||
@@ -175,6 +196,8 @@ export function toGfxBlockComponent<
|
||||
return class extends CustomBlock {
|
||||
[GfxElementSymbol] = true;
|
||||
|
||||
readonly transformState$ = signal<'idle' | 'active'>('active');
|
||||
|
||||
override selected$ = computed(() => {
|
||||
const selection = this.std.selection.value.find(
|
||||
selection => selection.blockId === this.model?.id
|
||||
|
||||
Reference in New Issue
Block a user