mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 06:47:02 +08:00
fix(editor): hide collpased content during dragging note (#10133)
Close [BS-2531](https://linear.app/affine-design/issue/BS-2531/%E6%8B%96%E5%8A%A8%E6%8A%98%E5%8F%A0%E7%9A%84note%E6%97%B6%EF%BC%8C%E4%B8%8D%E6%98%BE%E7%A4%BA%E9%9A%90%E8%97%8F%E5%86%85%E5%AE%B9), [BS-2536](https://linear.app/affine-design/issue/BS-2536/page-block%E9%A1%B6%E9%83%A8toolbar)
This commit is contained in:
@@ -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',
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user