fix: mini mindmap layout (#9276)

Fixes [BS-2197](https://linear.app/affine-design/issue/BS-2197/ai-生成-mindmap-预览异常)
This commit is contained in:
doouding
2024-12-24 06:55:25 +00:00
parent 338835a4aa
commit 4ead165dd5
3 changed files with 68 additions and 55 deletions

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line @typescript-eslint/triple-slash-reference // oxlint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="./effects.ts" /> /// <reference path="./effects.ts" />
export { type IModelCoord, ZOOM_MAX, ZOOM_MIN, ZOOM_STEP } from './consts.js'; export { type IModelCoord, ZOOM_MAX, ZOOM_MIN, ZOOM_STEP } from './consts.js';
export { GRID_GAP_MAX, GRID_GAP_MIN } from './consts.js'; export { GRID_GAP_MAX, GRID_GAP_MIN } from './consts.js';
@@ -29,6 +29,7 @@ export {
export { fitContent } from './renderer/elements/shape/utils.js'; export { fitContent } from './renderer/elements/shape/utils.js';
export * from './renderer/elements/type.js'; export * from './renderer/elements/type.js';
export { Overlay, OverlayIdentifier } from './renderer/overlay.js'; export { Overlay, OverlayIdentifier } from './renderer/overlay.js';
export { MindMapView } from './view/mindmap.js';
import { import {
getCursorByCoord, getCursorByCoord,
getLineHeight, getLineHeight,

View File

@@ -1,4 +1,7 @@
import { SurfaceBlockSchema } from '@blocksuite/affine-block-surface'; import {
MindMapView,
SurfaceBlockSchema,
} from '@blocksuite/affine-block-surface';
import { RootBlockSchema } from '@blocksuite/affine-model'; import { RootBlockSchema } from '@blocksuite/affine-model';
import { import {
DocModeService, DocModeService,
@@ -23,6 +26,7 @@ export const MiniMindmapSpecs: ExtensionType[] = [
MindmapService, MindmapService,
BlockViewExtension('affine:page', literal`mini-mindmap-root-block`), BlockViewExtension('affine:page', literal`mini-mindmap-root-block`),
FlavourExtension('affine:surface'), FlavourExtension('affine:surface'),
MindMapView,
MindmapSurfaceBlockService, MindmapSurfaceBlockService,
BlockViewExtension('affine:surface', literal`mini-mindmap-surface-block`), BlockViewExtension('affine:surface', literal`mini-mindmap-surface-block`),
]; ];

View File

@@ -12,9 +12,26 @@ import { wait } from '../utils/common.js';
import { getDocRootBlock } from '../utils/edgeless.js'; import { getDocRootBlock } from '../utils/edgeless.js';
import { setupEditor } from '../utils/setup.js'; import { setupEditor } from '../utils/setup.js';
describe('mind map', () => { describe('mini mindmap preview', () => {
let edgeless!: EdgelessRootBlockComponent; let edgeless!: EdgelessRootBlockComponent;
const createPreview = (host: EditorHost, answer: string) => {
const mindmapPreview = new MiniMindmapPreview();
mindmapPreview.answer = answer;
mindmapPreview.host = host;
mindmapPreview.ctx = {
get() {
return {};
},
set() {},
};
document.body.append(mindmapPreview);
return mindmapPreview;
};
beforeEach(async () => { beforeEach(async () => {
const cleanup = await setupEditor('edgeless'); const cleanup = await setupEditor('edgeless');
@@ -25,7 +42,7 @@ describe('mind map', () => {
return cleanup; return cleanup;
}); });
test('mind map preview', async () => { test('mini mindmap basic', async () => {
const mindmapAnswer = ` const mindmapAnswer = `
- Mindmap - Mindmap
- Node 1 - Node 1
@@ -36,74 +53,65 @@ describe('mind map', () => {
- Node 2.2 - Node 2.2
`; `;
const createPreview = ( const miniMindMapPreview = createPreview(
host: EditorHost, window.editor.host!,
answer: string = mindmapAnswer mindmapAnswer
) => { );
const mindmapPreview = new MiniMindmapPreview();
mindmapPreview.answer = answer;
mindmapPreview.host = host;
mindmapPreview.ctx = {
get() {
return {};
},
set() {},
};
document.body.append(mindmapPreview);
return mindmapPreview;
};
const miniMindMapPreview = createPreview(window.editor.host!);
await wait(50); await wait(50);
const miniMindMapSurface = miniMindMapPreview.renderRoot.querySelector( const miniMindMapSurface = miniMindMapPreview.renderRoot.querySelector(
'mini-mindmap-surface-block' 'mini-mindmap-surface-block'
) as MindmapSurfaceBlock; ) as MindmapSurfaceBlock;
expect(miniMindMapSurface).not.toBeNull(); // model-related properties
expect(miniMindMapPreview.mindmapId).toBeDefined();
expect(miniMindMapPreview.portalHost).toBeDefined();
expect(miniMindMapPreview.doc).toBeDefined();
expect(miniMindMapPreview.surface).toBeDefined();
expect(miniMindMapPreview.surface!.elementModels.length).toBe(8);
// renderer
expect(miniMindMapSurface.renderer).toBeDefined(); expect(miniMindMapSurface.renderer).toBeDefined();
expect(miniMindMapSurface.renderer?.canvas.isConnected).toBe(true); expect(miniMindMapSurface.renderer?.canvas.isConnected).toBe(true);
expect(miniMindMapSurface.renderer?.canvas.width).toBeGreaterThan(0); expect(miniMindMapSurface.renderer?.canvas.width).toBeGreaterThan(0);
expect(miniMindMapSurface.renderer?.canvas.height).toBeGreaterThan(0); expect(miniMindMapSurface.renderer?.canvas.height).toBeGreaterThan(0);
expect(miniMindMapSurface.model.elementModels.length).toBe(8);
return () => { return () => {
miniMindMapPreview.remove(); miniMindMapPreview.remove();
}; };
}); });
test('new mind map should layout automatically', async () => { test('mini mindmap should layout automatically', async () => {
const gfx = editor.std.get(GfxControllerIdentifier); const mindmapAnswer = `
const mindmapId = gfx.surface!.addElement({ - Main node
type: 'mindmap', - Child node
children: { - Second child node
text: 'Main node', - Third child node
children: [ `;
{
text: 'Child node',
},
{
text: 'Second child node',
},
{
text: 'Third child node',
},
],
},
});
const mindmap = gfx.getElementById(mindmapId) as MindmapElementModel;
await wait(0);
const [child1, child2, child3] = mindmap.tree.children;
expect(mindmapId).not.toBeUndefined(); const miniMindMapPreview = createPreview(
expect(mindmap.tree.children.length).toBe(3); window.editor.host!,
expect(mindmap.tree.element.x).toBeLessThan(child1.element.x); mindmapAnswer
);
await wait(50);
const gfx = miniMindMapPreview.portalHost.std.get(GfxControllerIdentifier);
const mindmap = gfx.surface!.elementModels.filter(
model => model.type === 'mindmap'
)[0] as MindmapElementModel;
const [child1, child2, child3] = mindmap.tree.children;
const root = mindmap.tree;
expect(mindmap).not.toBeUndefined();
expect(root.children.length).toBe(3);
expect(root.element.x).toBeLessThan(child1.element.x);
// children should be aligned horizontally
expect(child1.element.x).toBe(child2.element.x); expect(child1.element.x).toBe(child2.element.x);
expect(child2.element.x).toBe(child3.element.x); expect(child2.element.x).toBe(child3.element.x);
expect(child1.element.y).toBeLessThan(child2.element.y);
expect(child2.element.y).toBeLessThan(child3.element.y); // children
expect(child1.element.y + child1.element.h).toBeLessThan(child2.element.y);
expect(child2.element.y + child2.element.h).toBeLessThan(child3.element.y);
}); });
}); });