mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
fix(editor): can not undo and redo of color of edgeless blocks (#12414)
Close [BS-3507](https://linear.app/affine-design/issue/BS-3507/edgeless-text-颜色无法-undoredo) Close [BS-3426](https://linear.app/affine-design/issue/BS-3426/frame-修改背景色后不能撤销) This PR fixes the issue where the color change of edgeless blocks could not be undone/redone, including notes, edgeless-text, and frames. It also addresses the problem of a tiny shape being unexpectedly retained on the canvas. The key changes are: - Removal of `transact` from the `pop` method of edgeless elements. - Refactoring of `onPickColor` for all edgeless elements and blocks to better control the lifecycle of custom color property changes. - Addition of the missing custom background color feature for notes. - Addition of undo/redo color tests for notes, frames, and edgeless-text. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added undo and redo support for color changes in frames, notes, and text blocks, allowing users to revert or reapply background and text color modifications. - **Bug Fixes** - Improved reliability of color picker interactions, ensuring consistent state management and transactional updates during color changes. - **Tests** - Introduced new end-to-end tests to verify undo/redo functionality for color changes in frames, notes, and text blocks. - **Refactor** - Streamlined color picker event handling for better maintainability and consistency across toolbars and style panels. - Updated style panel structure and event handling for improved interaction and state management. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -2,7 +2,10 @@ import path from 'node:path';
|
||||
|
||||
import type { apis } from '@affine/electron-api';
|
||||
import { test } from '@affine-test/kit/electron';
|
||||
import { getBlockSuiteEditorTitle } from '@affine-test/kit/utils/page-logic';
|
||||
import {
|
||||
getBlockSuiteEditorTitle,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import {
|
||||
clickNewPageButton,
|
||||
clickSideBarCurrentWorkspaceBanner,
|
||||
@@ -99,8 +102,8 @@ test('export then add', async ({ page, appInfo, workspace }) => {
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// find button which has the title "test1"
|
||||
await page.getByText('test1').click();
|
||||
|
||||
await page.getByTestId('page-list-item').getByText('test1').click();
|
||||
await waitForEditorLoad(page);
|
||||
const title = page.locator('[data-block-is-title] >> text="test1"');
|
||||
await expect(title).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
autoFit,
|
||||
captureHistory,
|
||||
cutByKeyboard,
|
||||
dblclickView,
|
||||
dragBetweenIndices,
|
||||
edgelessCommonSetup,
|
||||
enterPlaygroundRoom,
|
||||
getEdgelessSelectedRect,
|
||||
getPageSnapshot,
|
||||
@@ -19,6 +21,7 @@ import {
|
||||
pressBackspace,
|
||||
pressEnter,
|
||||
pressEscape,
|
||||
redoByKeyboard,
|
||||
selectAllByKeyboard,
|
||||
setEdgelessTool,
|
||||
switchEditorMode,
|
||||
@@ -598,3 +601,62 @@ test('press backspace at the start of first line when edgeless text exist', asyn
|
||||
`${testInfo.title}_finial.json`
|
||||
);
|
||||
});
|
||||
|
||||
test('undo/redo should work when changing text color', async ({ page }) => {
|
||||
await edgelessCommonSetup(page);
|
||||
await dblclickView(page, [100, 100]);
|
||||
await type(page, 'abc');
|
||||
await pressEscape(page, 3);
|
||||
await waitNextFrame(page);
|
||||
|
||||
const edgelessText = page.locator('affine-edgeless-text');
|
||||
await edgelessText.click();
|
||||
|
||||
const getTextColor = async () => {
|
||||
return edgelessText.locator('span[data-v-text="true"]').evaluate(el => {
|
||||
return getComputedStyle(el).color;
|
||||
});
|
||||
};
|
||||
const colorPanel = page.locator('edgeless-color-picker-button');
|
||||
|
||||
let prevTextColor = await getTextColor();
|
||||
|
||||
// preset color
|
||||
{
|
||||
await colorPanel.click();
|
||||
await colorPanel.getByLabel('LightRed').click();
|
||||
expect(await getTextColor()).not.toBe(prevTextColor);
|
||||
|
||||
await undoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getTextColor()).toBe(prevTextColor);
|
||||
|
||||
await redoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getTextColor()).not.toBe(prevTextColor);
|
||||
}
|
||||
|
||||
prevTextColor = await getTextColor();
|
||||
|
||||
// custom color
|
||||
{
|
||||
await colorPanel.click();
|
||||
await colorPanel.locator('edgeless-color-custom-button').click();
|
||||
await page.locator('.color-palette').click({
|
||||
position: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
});
|
||||
await pressEscape(page);
|
||||
|
||||
expect(await getTextColor()).not.toBe(prevTextColor);
|
||||
await undoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getTextColor()).toBe(prevTextColor);
|
||||
|
||||
await redoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getTextColor()).not.toBe(prevTextColor);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,9 +24,11 @@ import {
|
||||
import {
|
||||
pressBackspace,
|
||||
pressEscape,
|
||||
redoByKeyboard,
|
||||
SHORT_KEY,
|
||||
undoByKeyboard,
|
||||
} from '../../utils/actions/keyboard.js';
|
||||
import { waitNextFrame } from '../../utils/actions/misc.js';
|
||||
import {
|
||||
assertCanvasElementsCount,
|
||||
assertContainerChildCount,
|
||||
@@ -420,3 +422,59 @@ test('undo should work when create a frame by dragging', async ({ page }) => {
|
||||
await undoByKeyboard(page);
|
||||
await expect(page.locator('affine-frame')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('undo/redo should work when change frame background', async ({ page }) => {
|
||||
await createFrame(page, [50, 50], [450, 450]);
|
||||
await pressEscape(page);
|
||||
|
||||
const frameTitle = page.locator('affine-frame-title');
|
||||
await frameTitle.click();
|
||||
|
||||
const getFrameBackground = async () => {
|
||||
return page.locator('affine-frame .affine-frame-container').evaluate(el => {
|
||||
return getComputedStyle(el).backgroundColor;
|
||||
});
|
||||
};
|
||||
const colorPanel = page.locator('edgeless-color-picker-button');
|
||||
|
||||
let prevBackground = await getFrameBackground();
|
||||
|
||||
// preset color
|
||||
{
|
||||
await colorPanel.click();
|
||||
await colorPanel.getByLabel('LightRed').click();
|
||||
expect(await getFrameBackground()).not.toBe(prevBackground);
|
||||
|
||||
await undoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getFrameBackground()).toBe(prevBackground);
|
||||
|
||||
await redoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getFrameBackground()).not.toBe(prevBackground);
|
||||
}
|
||||
|
||||
prevBackground = await getFrameBackground();
|
||||
|
||||
// custom color
|
||||
{
|
||||
await colorPanel.click();
|
||||
await colorPanel.locator('edgeless-color-custom-button').click();
|
||||
await page.locator('.color-palette').click({
|
||||
position: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
});
|
||||
await pressEscape(page);
|
||||
|
||||
expect(await getFrameBackground()).not.toBe(prevBackground);
|
||||
await undoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getFrameBackground()).toBe(prevBackground);
|
||||
|
||||
await redoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getFrameBackground()).not.toBe(prevBackground);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
initEmptyEdgelessState,
|
||||
initSixParagraphs,
|
||||
pasteByKeyboard,
|
||||
pressEscape,
|
||||
redoByClick,
|
||||
redoByKeyboard,
|
||||
selectNoteInEdgeless,
|
||||
@@ -137,3 +138,63 @@ test('continuous undo and redo (note block add operation) should work', async ({
|
||||
count = await countBlock(page, 'affine-edgeless-note');
|
||||
expect(count).toBe(4);
|
||||
});
|
||||
|
||||
test('undo/redo should work when change note custom background', async ({
|
||||
page,
|
||||
}) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
const { noteId } = await initEmptyEdgelessState(page);
|
||||
await switchEditorMode(page);
|
||||
await selectNoteInEdgeless(page, noteId);
|
||||
|
||||
const getNoteBackground = async () => {
|
||||
return page.locator('edgeless-note-background > div').evaluate(el => {
|
||||
return getComputedStyle(el).backgroundColor;
|
||||
});
|
||||
};
|
||||
|
||||
const stylePanel = page.locator('edgeless-note-style-panel');
|
||||
|
||||
let prevBackground = await getNoteBackground();
|
||||
|
||||
// preset color
|
||||
{
|
||||
await stylePanel.click();
|
||||
await stylePanel.getByLabel('Red').click();
|
||||
await pressEscape(page);
|
||||
|
||||
expect(await getNoteBackground()).not.toBe(prevBackground);
|
||||
await undoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getNoteBackground()).toBe(prevBackground);
|
||||
|
||||
await redoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getNoteBackground()).not.toBe(prevBackground);
|
||||
}
|
||||
|
||||
prevBackground = await getNoteBackground();
|
||||
|
||||
// custom color
|
||||
{
|
||||
await selectNoteInEdgeless(page, noteId);
|
||||
await stylePanel.click();
|
||||
await stylePanel.locator('edgeless-color-custom-button').click();
|
||||
await stylePanel.locator('.color-palette').click({
|
||||
position: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
});
|
||||
await pressEscape(page);
|
||||
|
||||
expect(await getNoteBackground()).not.toBe(prevBackground);
|
||||
await undoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getNoteBackground()).toBe(prevBackground);
|
||||
|
||||
await redoByKeyboard(page);
|
||||
await waitNextFrame(page);
|
||||
expect(await getNoteBackground()).not.toBe(prevBackground);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user