refactor(editor): cleanup dead code (#12072)

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

- **Refactor**
  - Simplified and removed several internal AI block extension files and utility functions, streamlining the codebase and reducing unused features.
  - Updated logic to access editor modes and controllers directly, removing reliance on DOM queries and certain abstractions.
  - Reduced and restructured effect type declarations for improved clarity.

- **Bug Fixes**
  - Improved type safety in the editor component by explicitly typing queried elements.

- **Chores**
  - Removed obsolete exports and internal functions with no impact on user-facing functionality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Saul-Mirone
2025-04-30 05:26:39 +00:00
parent 0d6c595adf
commit d856911144
12 changed files with 49 additions and 361 deletions
@@ -44,7 +44,6 @@ import { preprocessHtml } from '../utils/html';
import { fetchImageToFile } from '../utils/image';
import {
getCopilotSelectedElems,
getEdgelessRootFromEditor,
getSurfaceElementFromEditor,
} from '../utils/selection-utils';
import type { AffineAIPanelWidget } from '../widgets/ai-panel/ai-panel';
@@ -337,12 +336,12 @@ function responseToCreateImage(host: EditorHost) {
.then(img => {
if (!img) return;
const edgelessRoot = getEdgelessRootFromEditor(host);
const { minX, minY } = bounds;
const [x, y] = edgelessRoot.service.viewport.toViewCoord(minX, minY);
const gfx = host.std.get(GfxControllerIdentifier);
const [x, y] = gfx.viewport.toViewCoord(minX, minY);
host.doc.transact(() => {
addImages(edgelessRoot.std, [img], { point: [x, y] })
addImages(host.std, [img], { point: [x, y] })
.then(blockIds => {
const imageBlockId = blockIds[0];
const imageBlock = host.doc.getBlock(imageBlockId);
@@ -490,10 +489,8 @@ function responseToMakeItReal(host: EditorHost, ctx: AIContext) {
edgelessCopilot.hideCopilotPanel();
aiPanel.hide();
const edgelessRoot = getEdgelessRootFromEditor(host);
host.doc.transact(() => {
edgelessRoot.doc.addBlock(
host.doc.addBlock(
'affine:embed-html',
{
html,
@@ -1,9 +1,5 @@
import {
AffineCodeToolbarWidget,
CodeBlockSpec,
} from '@blocksuite/affine/blocks/code';
import { AffineCodeToolbarWidget } from '@blocksuite/affine/blocks/code';
import { LifeCycleWatcher } from '@blocksuite/affine/std';
import type { ExtensionType } from '@blocksuite/affine/store';
import { setupCodeToolbarAIEntry } from '../entries/code-toolbar/setup-code-toolbar';
@@ -24,8 +20,3 @@ export class AICodeBlockWatcher extends LifeCycleWatcher {
});
}
}
export const AICodeBlockSpec: ExtensionType[] = [
...CodeBlockSpec,
AICodeBlockWatcher,
];
@@ -1,14 +0,0 @@
import { ImageBlockSpec } from '@blocksuite/affine/blocks/image';
import { ToolbarModuleExtension } from '@blocksuite/affine/shared/services';
import { BlockFlavourIdentifier } from '@blocksuite/affine/std';
import type { ExtensionType } from '@blocksuite/affine/store';
import { imageToolbarAIEntryConfig } from '../entries/image-toolbar/setup-image-toolbar';
export const AIImageBlockSpec: ExtensionType[] = [
...ImageBlockSpec,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('custom:affine:image'),
config: imageToolbarAIEntryConfig(),
}),
];
@@ -1,24 +0,0 @@
import {
ParagraphBlockConfigExtension,
ParagraphBlockSpec,
} from '@blocksuite/affine/blocks/paragraph';
import type { ExtensionType } from '@blocksuite/affine/store';
export const AIParagraphBlockSpec: ExtensionType[] = [
...ParagraphBlockSpec,
ParagraphBlockConfigExtension({
getPlaceholder: model => {
const placeholders = {
text: "Type '/' for commands, 'space' for AI",
h1: 'Heading 1',
h2: 'Heading 2',
h3: 'Heading 3',
h4: 'Heading 4',
h5: 'Heading 5',
h6: 'Heading 6',
quote: '',
};
return placeholders[model.props.type];
},
}),
];
@@ -25,10 +25,8 @@ import { Slice, toDraftModel } from '@blocksuite/affine/store';
import type { ChatContextValue } from '../chat-panel/chat-context';
import {
allToCanvas,
getSelectedImagesAsBlobs,
getSelectedTextContent,
getTextContentFromBlockModels,
selectedToCanvas,
} from './selection-utils';
@@ -98,69 +96,6 @@ async function extractPageSelected(
}
}
export async function extractAllContent(
host: EditorHost
): Promise<Partial<ChatContextValue> | null> {
const docModeService = host.std.get(DocModeProvider);
const mode = docModeService.getEditorMode() || 'page';
if (mode === 'edgeless') {
return await extractEdgelessAll(host);
} else {
return await extractPageAll(host);
}
}
export async function extractEdgelessAll(
host: EditorHost
): Promise<Partial<ChatContextValue> | null> {
if (!isInsideEdgelessEditor(host)) return null;
const canvas = await allToCanvas(host);
if (!canvas) return null;
const blob: Blob | null = await new Promise(resolve =>
canvas.toBlob(resolve)
);
if (!blob) return null;
return {
images: [new File([blob], `${host.doc.id}.png`)],
};
}
export async function extractPageAll(
host: EditorHost
): Promise<Partial<ChatContextValue> | null> {
const blockModels = getNoteBlockModels(host.doc);
const text = await getTextContentFromBlockModels(
host,
blockModels,
'plain-text'
);
const markdown = await getTextContentFromBlockModels(
host,
blockModels,
'markdown'
);
const blobs = await Promise.all(
blockModels.map(async s => {
if (s.flavour !== 'affine:image') return null;
const sourceId = (s as ImageBlockModel)?.props.sourceId;
if (!sourceId) return null;
const blob = await (sourceId ? host.doc.blobSync.get(sourceId) : null);
if (!blob) return null;
return new File([blob], sourceId);
}) ?? []
);
const images = blobs.filter((blob): blob is File => !!blob);
return {
quote: text,
markdown,
images,
};
}
export async function extractMarkdownFromDoc(
doc: Store,
provider: ServiceProvider
@@ -1,17 +1,12 @@
import {
EdgelessClipboardController,
isCanvasElement,
splitElements,
} from '@blocksuite/affine/blocks/root';
import {
getSurfaceBlock,
type SurfaceBlockComponent,
} from '@blocksuite/affine/blocks/surface';
import {
DatabaseBlockModel,
type FrameBlockModel,
ImageBlockModel,
} from '@blocksuite/affine/model';
import { DatabaseBlockModel, ImageBlockModel } from '@blocksuite/affine/model';
import {
getBlockSelectionsCommand,
getImageSelectionsCommand,
@@ -36,30 +31,17 @@ import { getContentFromSlice } from '../../utils';
import type { CopilotTool } from '../tool/copilot-tool';
import { getEdgelessCopilotWidget } from './edgeless';
export function getEdgelessRootFromEditor(editor: EditorHost) {
const edgelessRoot = editor.getElementsByTagName('affine-edgeless-root')[0];
if (!edgelessRoot) {
alert('Please switch to edgeless mode');
throw new Error('Please open switch to edgeless mode');
}
return edgelessRoot;
}
export async function selectedToCanvas(host: EditorHost) {
const edgelessRoot = getEdgelessRootFromEditor(host);
return elementsToCanvas(
host,
edgelessRoot.service.selection.selectedElements
);
const gfx = host.std.get(GfxControllerIdentifier);
return elementsToCanvas(host, gfx.selection.selectedElements);
}
export async function allToCanvas(host: EditorHost) {
const edgelessRoot = getEdgelessRootFromEditor(host);
return elementsToCanvas(host, edgelessRoot.gfx.gfxElements);
const gfx = host.std.get(GfxControllerIdentifier);
return elementsToCanvas(host, gfx.gfxElements);
}
export async function elementsToCanvas(host: EditorHost, elements: GfxModel[]) {
const edgelessRoot = getEdgelessRootFromEditor(host);
const { notes, frames, shapes, images, edgelessTexts, embedSyncedDocs } =
splitElements(elements);
@@ -77,7 +59,7 @@ export async function elementsToCanvas(host: EditorHost, elements: GfxModel[]) {
}
try {
const canvas = await edgelessRoot.std
const canvas = await host.std
.get(EdgelessClipboardController)
.toCanvas(blockElements, shapes);
if (!canvas) {
@@ -90,10 +72,6 @@ export async function elementsToCanvas(host: EditorHost, elements: GfxModel[]) {
}
}
export async function selectedToPng(editor: EditorHost) {
return (await selectedToCanvas(editor))?.toDataURL('image/png');
}
export function getSelectedModels(editorHost: EditorHost) {
const [_, ctx] = editorHost.std.command.exec(getSelectedModelsCommand, {
types: ['block', 'text'],
@@ -198,10 +176,6 @@ export async function selectAboveBlocks(editorHost: EditorHost, num = 10) {
return getTextContentFromBlockModels(editorHost, selectedModels);
}
export const stopPropagation = (e: Event) => {
e.stopPropagation();
};
export function getSurfaceElementFromEditor(editor: EditorHost) {
const { doc } = editor;
const surfaceModel = getSurfaceBlock(doc);
@@ -216,24 +190,6 @@ export function getSurfaceElementFromEditor(editor: EditorHost) {
return surfaceElement;
}
export const getFirstImageInFrame = (
frame: FrameBlockModel,
editor: EditorHost
) => {
const edgelessRoot = getEdgelessRootFromEditor(editor);
const elements = edgelessRoot.service.frame.getElementsInFrameBound(
frame,
false
);
const image = elements.find(ele => {
if (!isCanvasElement(ele)) {
return ele.flavour === 'affine:image';
}
return false;
}) as ImageBlockModel | undefined;
return image?.id;
};
export const getSelections = (
host: EditorHost,
mode: 'flat' | 'highest' = 'flat'
@@ -1,8 +1,5 @@
import { registerAIEffects } from '@affine/core/blocksuite/ai/effects';
import { editorEffects } from '@affine/core/blocksuite/editors';
import type * as EffectType from '@blocksuite/affine/effects';
declare type _GLOBAL_ = typeof EffectType;
import { registerTemplates } from './register-templates';
@@ -401,7 +401,9 @@ export const BlocksuiteEdgelessEditor = forwardRef<
editorRef.current.updateComplete
.then(() => {
// make sure editor can get keyboard events on showing up
editorRef.current?.querySelector('affine-edgeless-root')?.click();
editorRef.current
?.querySelector<HTMLElement>('affine-edgeless-root')
?.click();
})
.catch(console.error);
}
@@ -3,7 +3,10 @@ import type { DefaultOpenProperty } from '@affine/core/components/doc-properties
import type { DocTitle } from '@blocksuite/affine/fragments/doc-title';
import type { DocMode, ReferenceParams } from '@blocksuite/affine/model';
import { HighlightSelection } from '@blocksuite/affine/shared/selection';
import { FeatureFlagService as BSFeatureFlagService } from '@blocksuite/affine/shared/services';
import {
DocModeProvider,
FeatureFlagService as BSFeatureFlagService,
} from '@blocksuite/affine/shared/services';
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
import type { InlineEditor } from '@blocksuite/std/inline';
import { effect } from '@preact/signals-core';
@@ -293,19 +296,18 @@ export class Editor extends Entity {
unsubs.push(subscription.unsubscribe.bind(subscription));
// ----- Presenting -----
const edgelessPage = editorContainer.host?.querySelector(
'affine-edgeless-root'
);
if (!edgelessPage) {
const std = editorContainer.host?.std;
const editorMode = std?.get(DocModeProvider)?.getEditorMode();
if (!editorMode || editorMode !== 'edgeless' || !gfx) {
this.isPresenting$.next(false);
} else {
this.isPresenting$.next(
edgelessPage.gfx.tool.currentToolName$.peek() === 'frameNavigator'
gfx.tool.currentToolName$.peek() === 'frameNavigator'
);
const disposable = effect(() => {
this.isPresenting$.next(
edgelessPage.gfx.tool.currentToolName$.value === 'frameNavigator'
gfx.tool.currentToolName$.value === 'frameNavigator'
);
});
unsubs.push(disposable);