refactor(editor): remove global types in model (#10082)

Closes: [BS-2249](https://linear.app/affine-design/issue/BS-2249/remove-global-types-in-model)

```ts
// before
matchFlavours(model, ['affine:page']);
// after
matchFlavours(model, [PageBlockModel]);
```
This commit is contained in:
Saul-Mirone
2025-02-11 08:18:57 +00:00
parent 64bb6c5a71
commit 652865c7cf
97 changed files with 492 additions and 323 deletions

View File

@@ -17,6 +17,7 @@ import {
getSelectedBlocksCommand,
NoteDisplayMode,
NotificationProvider,
ParagraphBlockModel,
RefNodeSlotsProvider,
TelemetryProvider,
} from '@blocksuite/affine/blocks';
@@ -166,7 +167,7 @@ function addAIChatBlock(
const y = viewportCenter.y - height / 2;
const bound = new Bound(x, y, width, height);
const aiChatBlockId = doc.addBlock(
'affine:embed-ai-chat' as keyof BlockSuite.BlockModels,
'affine:embed-ai-chat',
{
xywh: bound.serialize(),
messages: JSON.stringify(messages),
@@ -231,7 +232,7 @@ const REPLACE_SELECTION = {
if (currentTextSelection) {
const { doc } = host;
const block = doc.getBlock(currentTextSelection.blockId);
if (matchFlavours(block?.model ?? null, ['affine:paragraph'])) {
if (matchFlavours(block?.model ?? null, [ParagraphBlockModel])) {
block?.model.text?.replace(
currentTextSelection.from.index,
currentTextSelection.from.length,

View File

@@ -2,8 +2,12 @@ import type { Chain, InitCommandCtx } from '@blocksuite/affine/block-std';
import {
type AIItemGroupConfig,
type AISubItemConfig,
CodeBlockModel,
getSelectedModelsCommand,
ImageBlockModel,
ListBlockModel,
matchFlavours,
ParagraphBlockModel,
} from '@blocksuite/affine/blocks';
import { actionToHandler } from '../actions/doc-handler';
@@ -103,7 +107,7 @@ const textBlockShowWhen = (chain: Chain<InitCommandCtx>) => {
if (!selectedModels || selectedModels.length === 0) return false;
return selectedModels.some(model =>
matchFlavours(model, ['affine:paragraph', 'affine:list'])
matchFlavours(model, [ParagraphBlockModel, ListBlockModel])
);
};
@@ -117,7 +121,7 @@ const codeBlockShowWhen = (chain: Chain<InitCommandCtx>) => {
if (!selectedModels || selectedModels.length > 1) return false;
const model = selectedModels[0];
return matchFlavours(model, ['affine:code']);
return matchFlavours(model, [CodeBlockModel]);
};
const imageBlockShowWhen = (chain: Chain<InitCommandCtx>) => {
@@ -130,7 +134,7 @@ const imageBlockShowWhen = (chain: Chain<InitCommandCtx>) => {
if (!selectedModels || selectedModels.length > 1) return false;
const model = selectedModels[0];
return matchFlavours(model, ['affine:image']);
return matchFlavours(model, [ImageBlockModel]);
};
const EditAIGroup: AIItemGroupConfig = {
@@ -278,7 +282,7 @@ const GenerateWithAIGroup: AIItemGroupConfig = {
return selectedModels.every(
model =>
matchFlavours(model, ['affine:paragraph', 'affine:list']) &&
matchFlavours(model, [ParagraphBlockModel, ListBlockModel]) &&
!model.type.startsWith('h')
);
},

View File

@@ -7,6 +7,7 @@ import type {
} from '@blocksuite/affine/blocks';
import {
BlocksUtils,
CodeBlockModel,
EdgelessTextBlockModel,
EmbedSyncedDocModel,
ImageBlockModel,
@@ -485,7 +486,7 @@ export function noteWithCodeBlockShowWen(
return (
selected[0] instanceof NoteBlockModel &&
selected[0].children.length === 1 &&
BlocksUtils.matchFlavours(selected[0].children[0], ['affine:code'])
BlocksUtils.matchFlavours(selected[0].children[0], [CodeBlockModel])
);
}

View File

@@ -527,7 +527,7 @@ async function responseToCreateSlides(host: EditorHost, ctx: AIContext) {
await job.insertTemplate(content);
}
getSurfaceElementFromEditor(host).refresh();
getSurfaceElementFromEditor(host)?.refresh();
} catch (error) {
console.error('Error creating slides:', error);
}

View File

@@ -7,6 +7,7 @@ import {
ImageBlockModel,
isInsideEdgelessEditor,
matchFlavours,
NoteBlockModel,
NoteDisplayMode,
} from '@blocksuite/affine/blocks';
import { assertExists, Bound } from '@blocksuite/affine/global/utils';
@@ -115,7 +116,7 @@ function createNewNote(host: EditorHost): AIItemConfig {
// set the viewport to show the new note block and original note block
const newNote = doc.getBlock(noteBlockId)?.model;
if (!newNote || !matchFlavours(newNote, ['affine:note'])) return;
if (!newNote || !matchFlavours(newNote, [NoteBlockModel])) return;
const newNoteBound = Bound.deserialize(newNote.xywh);
const bounds = [bound, newNoteBound];
service.gfx.fitToScreen({

View File

@@ -175,7 +175,7 @@ export class AIChatBlockPeekView extends LitElement {
const edgelessService = this._rootService as EdgelessRootService;
const bound = calcChildBound(this.parentModel, edgelessService);
const aiChatBlockId = edgelessService.crud.addBlock(
'affine:embed-ai-chat' as keyof BlockSuite.BlockModels,
'affine:embed-ai-chat',
{
xywh: bound.serialize(),
messages: JSON.stringify(messages),

View File

@@ -51,7 +51,7 @@ export const PPTBuilder = (host: EditorHost) => {
);
}
await job.insertTemplate(content);
getSurfaceElementFromEditor(host).refresh();
getSurfaceElementFromEditor(host)?.refresh();
};
return {

View File

@@ -5,7 +5,10 @@ import {
type EdgelessRootService,
matchFlavours,
MindmapElementModel,
NoteBlockModel,
RootBlockModel,
type ShapeElementModel,
SurfaceBlockModel,
} from '@blocksuite/affine/blocks';
export function mindMapToMarkdown(mindmap: MindmapElementModel) {
@@ -62,10 +65,10 @@ export function getEdgelessCopilotWidget(
export function findNoteBlockModel(blockElement: BlockComponent) {
let curBlock = blockElement;
while (curBlock) {
if (matchFlavours(curBlock.model, ['affine:note'])) {
if (matchFlavours(curBlock.model, [NoteBlockModel])) {
return curBlock.model;
}
if (matchFlavours(curBlock.model, ['affine:page', 'affine:surface'])) {
if (matchFlavours(curBlock.model, [RootBlockModel, SurfaceBlockModel])) {
return null;
}
if (!curBlock.parentComponent) {

View File

@@ -1,11 +1,12 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import {
BlocksUtils,
DatabaseBlockModel,
DocModeProvider,
embedSyncedDocMiddleware,
getImageSelectionsCommand,
getSelectedBlocksCommand,
type ImageBlockModel,
ImageBlockModel,
isInsideEdgelessEditor,
MarkdownAdapter,
type NoteBlockModel,
@@ -163,7 +164,7 @@ export async function extractMarkdownFromDoc(
const blockModels = getNoteBlockModels(doc);
const textModels = blockModels.filter(
model =>
!BlocksUtils.matchFlavours(model, ['affine:image', 'affine:database'])
!BlocksUtils.matchFlavours(model, [ImageBlockModel, DatabaseBlockModel])
);
const drafts = textModels.map(toDraftModel);
const slice = Slice.fromModels(doc, drafts);

View File

@@ -3,6 +3,7 @@ import type { GfxModel } from '@blocksuite/affine/block-std/gfx';
import {
BlocksUtils,
type CopilotTool,
DatabaseBlockModel,
EdgelessRootService,
type FrameBlockModel,
getBlockSelectionsCommand,
@@ -13,7 +14,6 @@ import {
ImageBlockModel,
type SurfaceBlockComponent,
} from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
import {
type BlockModel,
type DraftModel,
@@ -134,7 +134,7 @@ export async function getTextContentFromBlockModels(
// Currently only filter out images and databases
const selectedTextModels = models.filter(
model =>
!BlocksUtils.matchFlavours(model, ['affine:image', 'affine:database'])
!BlocksUtils.matchFlavours(model, [ImageBlockModel, DatabaseBlockModel])
);
const drafts = selectedTextModels.map(toDraftModel);
drafts.forEach(draft => traverse(draft, drafts));
@@ -147,13 +147,13 @@ export async function getSelectedTextContent(
type: 'markdown' | 'plain-text' = 'markdown'
) {
const selectedModels = getSelectedModels(editorHost);
assertExists(selectedModels);
if (!selectedModels) return '';
return getTextContentFromBlockModels(editorHost, selectedModels, type);
}
export async function selectAboveBlocks(editorHost: EditorHost, num = 10) {
let selectedModels = getSelectedModels(editorHost);
assertExists(selectedModels);
if (!selectedModels) return '';
const lastLeafModel = selectedModels[selectedModels.length - 1];
@@ -163,8 +163,7 @@ export async function selectAboveBlocks(editorHost: EditorHost, num = 10) {
lastRootModel = noteModel;
noteModel = editorHost.doc.getParent(noteModel);
}
assertExists(noteModel);
assertExists(lastRootModel);
if (!noteModel || !lastRootModel) return '';
const endIndex = noteModel.children.indexOf(lastRootModel) + 1;
const startIndex = Math.max(0, endIndex - num);
@@ -212,13 +211,13 @@ export const stopPropagation = (e: Event) => {
export function getSurfaceElementFromEditor(editor: EditorHost) {
const { doc } = editor;
const surfaceModel = doc.getBlockByFlavour('affine:surface')[0];
assertExists(surfaceModel);
if (!surfaceModel) return null;
const surfaceId = surfaceModel.id;
const surfaceElement = editor.querySelector(
`affine-surface[data-block-id="${surfaceId}"]`
) as SurfaceBlockComponent;
assertExists(surfaceElement);
if (!surfaceElement) return null;
return surfaceElement;
}

View File

@@ -11,7 +11,7 @@ import { track } from '@affine/track';
import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx';
import {
matchFlavours,
type NoteBlockModel,
NoteBlockModel,
NoteDisplayMode,
} from '@blocksuite/affine/blocks';
import { Bound } from '@blocksuite/affine/global/utils';
@@ -176,7 +176,7 @@ export const EdgelessNoteHeader = ({ note }: { note: NoteBlockModel }) => {
const isFirstVisibleNote =
note.parent?.children.find(
child =>
matchFlavours(child, ['affine:note']) &&
matchFlavours(child, [NoteBlockModel]) &&
child.displayMode === NoteDisplayMode.DocAndEdgeless
) === note;