feat(editor): add basic note support in turbo renderer (#11607)

After landing layout tree refactoring, this PR adds basic note support in turbo renderer.

In this demo recording, the code and image block needs to be further supported.

[Screen Recording 2025-04-10 at 5.16.15 PM.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/lEGcysB4lFTEbCwZ8jMv/2e416b41-5609-4e52-a90f-5b7bb77db682.mov" />](https://app.graphite.dev/media/video/lEGcysB4lFTEbCwZ8jMv/2e416b41-5609-4e52-a90f-5b7bb77db682.mov)
This commit is contained in:
doodlewind
2025-04-10 09:52:33 +00:00
parent 69d4620753
commit dba8e00fb6
11 changed files with 337 additions and 181 deletions
@@ -0,0 +1,81 @@
import type { Rect } from '@blocksuite/affine-gfx-turbo-renderer';
import {
BlockLayoutHandlerExtension,
BlockLayoutHandlersIdentifier,
} from '@blocksuite/affine-gfx-turbo-renderer';
import {
ColorScheme,
type NoteBlockModel,
resolveColor,
} from '@blocksuite/affine-model';
import type { Container } from '@blocksuite/global/di';
import type { EditorHost, GfxBlockComponent } from '@blocksuite/std';
import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx';
import type { BlockModel } from '@blocksuite/store';
import type { NoteLayout } from './note-painter.worker';
export class NoteLayoutHandlerExtension extends BlockLayoutHandlerExtension<NoteLayout> {
readonly blockType = 'affine:note';
static override setup(di: Container) {
di.addImpl(
BlockLayoutHandlersIdentifier('note'),
NoteLayoutHandlerExtension
);
}
override queryLayout(
model: BlockModel,
host: EditorHost,
viewportRecord: ViewportRecord
): NoteLayout | null {
const component = host.std.view.getBlock(model.id) as GfxBlockComponent;
if (!component) return null;
// Get the note container element
const noteContainer = component.querySelector('.affine-note-mask');
if (!noteContainer) return null;
// Get the bounding client rect of the note container
const clientRect = noteContainer.getBoundingClientRect();
// Convert client coordinates to model coordinates
const [modelX, modelY] = clientToModelCoord(viewportRecord, [
clientRect.x,
clientRect.y,
]);
const { zoom, viewScale } = viewportRecord;
// Cast model to NoteBlockModel to access background property from props
const noteModel = model as NoteBlockModel;
const background = noteModel.props.background;
// Resolve the color to a string
const backgroundString = resolveColor(background, ColorScheme.Light);
// Create the note layout object
const noteLayout: NoteLayout = {
type: 'affine:note',
blockId: model.id,
rect: {
x: modelX,
y: modelY,
w: clientRect.width / zoom / viewScale,
h: clientRect.height / zoom / viewScale,
},
background: backgroundString,
};
return noteLayout;
}
calculateBound(layout: NoteLayout) {
const rect: Rect = layout.rect;
return {
rect,
subRects: [rect], // The note is represented by a single rectangle
};
}
}