L-Sun
2025-02-13 04:18:11 +00:00
parent 01b9aa91b2
commit 011c18de8b
4 changed files with 138 additions and 3 deletions

View File

@@ -26,12 +26,13 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent(
return ( return (
this.model.edgeless.collapse && this.model.edgeless.collapse &&
this.gfx.selection.has(this.model.id) && this.gfx.selection.has(this.model.id) &&
!this._dragging &&
(this._isResizing || this._isHover) (this._isResizing || this._isHover)
); );
} }
get _zoom() { private get _dragging() {
return this.gfx.viewport.zoom; return this._isHover && this.gfx.tool.dragging$.value;
} }
private _collapsedContent() { private _collapsedContent() {
@@ -236,6 +237,7 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent(
></edgeless-note-background> ></edgeless-note-background>
<div <div
data-testid="edgeless-note-clip-container"
class=${styles.clipContainer} class=${styles.clipContainer}
style=${styleMap({ style=${styleMap({
'overflow-y': this._isShowCollapsedContent ? 'initial' : 'clip', 'overflow-y': this._isShowCollapsedContent ? 'initial' : 'clip',

View File

@@ -28,6 +28,7 @@ const buttonPadding = 4;
export const button = style({ export const button = style({
padding: buttonPadding, padding: buttonPadding,
pointerEvents: 'auto', pointerEvents: 'auto',
color: cssVarV2('icon/transparentBlack'),
}); });
export const headerHeight = 2 * headerPadding + iconSize + 2 * buttonPadding; export const headerHeight = 2 * headerPadding + iconSize + 2 * buttonPadding;

View File

@@ -5,14 +5,19 @@ import {
createEdgelessNoteBlock, createEdgelessNoteBlock,
getEdgelessSelectedIds, getEdgelessSelectedIds,
getPageMode, getPageMode,
getSelectedXYWH,
locateEditorContainer, locateEditorContainer,
locateElementToolbar, locateElementToolbar,
locateModeSwitchButton, locateModeSwitchButton,
moveToView,
resizeElementByHandle,
toViewCoord,
} from '@affine-test/kit/utils/editor'; } from '@affine-test/kit/utils/editor';
import { import {
pasteByKeyboard, pasteByKeyboard,
pressBackspace, pressBackspace,
pressEnter, pressEnter,
pressEscape,
selectAllByKeyboard, selectAllByKeyboard,
undoByKeyboard, undoByKeyboard,
} from '@affine-test/kit/utils/keyboard'; } from '@affine-test/kit/utils/keyboard';
@@ -27,6 +32,7 @@ import type {
EdgelessRootBlockComponent, EdgelessRootBlockComponent,
NoteBlockModel, NoteBlockModel,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import type { IVec } from '@blocksuite/global/utils';
import { expect, type Page } from '@playwright/test'; import { expect, type Page } from '@playwright/test';
const title = 'Edgeless Note Header Test'; const title = 'Edgeless Note Header Test';
@@ -370,3 +376,54 @@ test.describe('edgeless note element toolbar', () => {
}); });
}); });
}); });
test.describe('note block rendering', () => {
test('collapsed content rendering', async ({ page }) => {
await createEdgelessNoteBlock(page, [50, 50]);
await type(page, 'paragraph 1');
for (let i = 0; i < 5; i++) {
await pressEnter(page);
}
await type(page, 'paragraph 2');
await pressEscape(page, 3);
await clickView(page, [50, 50]);
await resizeElementByHandle(page, [0, -50], 'bottom-right');
const xywh = await getSelectedXYWH(page);
const center: IVec = [xywh[0] + xywh[2] / 2, xywh[1] + xywh[3] / 2];
const note = page
.locator('affine-edgeless-note')
.getByTestId('edgeless-note-clip-container')
.nth(1);
await expect(note, 'should hide collapsed content').toHaveCSS(
'overflow-y',
'clip'
);
await moveToView(page, center);
await expect(note, 'should show collapsed content when hover').toHaveCSS(
'overflow-y',
'visible'
);
const [x1, y1] = await toViewCoord(page, center);
const [x2, y2] = await toViewCoord(page, [center[0], center[1] + 25]);
const [x3, y3] = await toViewCoord(page, [center[0], center[1] + 50]);
await page.mouse.move(x1, y1);
await page.mouse.down();
await page.mouse.move(x2, y2, { steps: 10 });
await expect(
note,
'should hide collapsed content during dragging'
).toHaveCSS('overflow-y', 'clip');
await page.mouse.move(x3, y3, { steps: 10 });
await page.mouse.up();
await page.mouse.move(x3, y3);
await expect(
note,
'should show collapsed content when dragging is finished'
).toHaveCSS('overflow-y', 'visible');
});
});

View File

@@ -82,6 +82,22 @@ export async function getEdgelessSelectedIds(page: Page, editorIndex = 0) {
}); });
} }
export async function getSelectedXYWH(
page: Page,
index = 0,
editorIndex = 0
): Promise<[number, number, number, number]> {
const container = locateEditorContainer(page, editorIndex);
return container.evaluate((container, index) => {
const root = container.querySelector('affine-edgeless-root');
if (!root) {
throw new Error('Edgeless root not found');
}
const selected = root.service.selection.selectedElements[index];
return selected.elementBound.toXYWH();
}, index);
}
export async function getViewportCenter(page: Page, editorIndex = 0) { export async function getViewportCenter(page: Page, editorIndex = 0) {
const container = locateEditorContainer(page, editorIndex); const container = locateEditorContainer(page, editorIndex);
return container.evaluate((container: AffineEditorContainer) => { return container.evaluate((container: AffineEditorContainer) => {
@@ -108,6 +124,17 @@ export async function setViewportCenter(
}, center); }, center);
} }
export async function setViewportZoom(page: Page, zoom = 1, editorIndex = 0) {
const container = locateEditorContainer(page, editorIndex);
return container.evaluate((container: AffineEditorContainer, zoom) => {
const root = container.querySelector('affine-edgeless-root');
if (!root) {
throw new Error('Edgeless root not found');
}
root.gfx.viewport.setZoom(zoom);
}, zoom);
}
/** /**
* Convert a canvas point to view coordinate * Convert a canvas point to view coordinate
* @param point the coordinate on the canvas * @param point the coordinate on the canvas
@@ -119,10 +146,36 @@ export async function toViewCoord(page: Page, point: IVec, editorIndex = 0) {
if (!root) { if (!root) {
throw new Error('Edgeless root not found'); throw new Error('Edgeless root not found');
} }
return root.gfx.viewport.toViewCoord(point[0], point[1]); const coord = root.gfx.viewport.toViewCoord(point[0], point[1]);
coord[0] += root.gfx.viewport.left;
coord[1] += root.gfx.viewport.top;
return coord;
}, point); }, point);
} }
/**
* Convert a view coordinate to canvas point
* @param point the coordinate on the view
*/
export async function toModelCoord(page: Page, point: IVec, editorIndex = 0) {
const container = locateEditorContainer(page, editorIndex);
return container.evaluate((container: AffineEditorContainer, point) => {
const root = container.querySelector('affine-edgeless-root');
if (!root) {
throw new Error('Edgeless root not found');
}
return root.gfx.viewport.toModelCoordFromClientCoord(point);
}, point);
}
/**
* Move to a point on the canvas
*/
export async function moveToView(page: Page, point: IVec, editorIndex = 0) {
const [x, y] = await toViewCoord(page, point, editorIndex);
await page.mouse.move(x, y);
}
/** /**
* Click a point on the canvas * Click a point on the canvas
* @param point the coordinate on the canvas * @param point the coordinate on the canvas
@@ -331,6 +384,28 @@ export async function setEdgelessTool(
} }
} }
export async function resizeElementByHandle(
page: Page,
delta: IVec,
corner:
| 'top-left'
| 'top-right'
| 'bottom-right'
| 'bottom-left' = 'top-left',
editorIndex = 0
) {
const handle = page.locator(`.handle[aria-label="${corner}"] .resize`);
const box = await handle.boundingBox();
if (box === null) throw new Error();
const from = await toModelCoord(
page,
[box.x + box.width / 2, box.y + box.height / 2],
editorIndex
);
const to: IVec = [from[0] + delta[0], from[1] + delta[1]];
await dragView(page, from, to, editorIndex);
}
export function locateElementToolbar(page: Page, editorIndex = 0) { export function locateElementToolbar(page: Page, editorIndex = 0) {
return locateEditorContainer(page, editorIndex).locator( return locateEditorContainer(page, editorIndex).locator(
EDGELESS_ELEMENT_TOOLBAR_WIDGET EDGELESS_ELEMENT_TOOLBAR_WIDGET