feat(editor): add toolbar registry extension (#9572)
### What's Changed! #### Added Manage various types of toolbars uniformly in one place. * `affine-toolbar-widget` * `ToolbarRegistryExtension` The toolbar currently supports and handles several scenarios: 1. Select blocks: `BlockSelection` 2. Select text: `TextSelection` or `NativeSelection` 3. Hover a link: `affine-link` and `affine-reference` #### Removed Remove redundant toolbar implementations. * `attachment` toolbar * `bookmark` toolbar * `embed` toolbar * `formatting` toolbar * `affine-link` toolbar * `affine-reference` toolbar ### How to migrate? Here is an example that can help us migrate some unrefactored toolbars: Check out the more detailed types of [`ToolbarModuleConfig`](c178debf2d/blocksuite/affine/shared/src/services/toolbar-service/config.ts). 1. Add toolbar configuration file to a block type, such as bookmark block: [`config.ts`](c178debf2d/blocksuite/affine/block-bookmark/src/configs/toolbar.ts) ```ts export const builtinToolbarConfig = { actions: [ { id: 'a.preview', content(ctx) { const model = ctx.getCurrentModelBy(BlockSelection, BookmarkBlockModel); if (!model) return null; const { url } = model; return html`<affine-link-preview .url=${url}></affine-link-preview>`; }, }, { id: 'b.conversions', actions: [ { id: 'inline', label: 'Inline view', run(ctx) { }, }, { id: 'card', label: 'Card view', disabled: true, }, { id: 'embed', label: 'Embed view', disabled(ctx) { }, run(ctx) { }, }, ], content(ctx) { }, } satisfies ToolbarActionGroup<ToolbarAction>, { id: 'c.style', actions: [ { id: 'horizontal', label: 'Large horizontal style', }, { id: 'list', label: 'Small horizontal style', }, ], content(ctx) { }, } satisfies ToolbarActionGroup<ToolbarAction>, { id: 'd.caption', tooltip: 'Caption', icon: CaptionIcon(), run(ctx) { }, }, { placement: ActionPlacement.More, id: 'a.clipboard', actions: [ { id: 'copy', label: 'Copy', icon: CopyIcon(), run(ctx) { }, }, { id: 'duplicate', label: 'Duplicate', icon: DuplicateIcon(), run(ctx) { }, }, ], }, { placement: ActionPlacement.More, id: 'b.refresh', label: 'Reload', icon: ResetIcon(), run(ctx) { }, }, { placement: ActionPlacement.More, id: 'c.delete', label: 'Delete', icon: DeleteIcon(), variant: 'destructive', run(ctx) { }, }, ], } as const satisfies ToolbarModuleConfig; ``` 2. Add configuration extension to a block spec: [bookmark's spec](c178debf2d/blocksuite/affine/block-bookmark/src/bookmark-spec.ts) ```ts const flavour = BookmarkBlockSchema.model.flavour; export const BookmarkBlockSpec: ExtensionType[] = [ ..., ToolbarModuleExtension({ id: BlockFlavourIdentifier(flavour), config: builtinToolbarConfig, }), ].flat(); ``` 3. If the bock type already has a toolbar configuration built in, we can customize it in the following ways: Check out the [editor's config](c178debf2d/packages/frontend/core/src/blocksuite/extensions/editor-config/index.ts (L51C4-L54C8)) file. ```ts // Defines a toolbar configuration for the bookmark block type const customBookmarkToolbarConfig = { actions: [ ... ] } as const satisfies ToolbarModuleConfig; // Adds it into the editor's config ToolbarModuleExtension({ id: BlockFlavourIdentifier('custom:affine:bookmark'), config: customBookmarkToolbarConfig, }), ``` 4. If we want to extend the global: ```ts // Defines a toolbar configuration const customWildcardToolbarConfig = { actions: [ ... ] } as const satisfies ToolbarModuleConfig; // Adds it into the editor's config ToolbarModuleExtension({ id: BlockFlavourIdentifier('custom:affine:*'), config: customWildcardToolbarConfig, }), ``` Currently, only most toolbars in page mode have been refactored. Next is edgeless mode.
This commit is contained in:
@@ -51,7 +51,7 @@ const FILE_PATH = path.resolve(
|
||||
function getAttachment(page: Page) {
|
||||
const attachment = page.locator('affine-attachment');
|
||||
const loading = attachment.locator('.affine-attachment-card.loading');
|
||||
const toolbar = page.locator('.affine-attachment-toolbar');
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
const switchViewButton = toolbar.getByRole('button', { name: 'Switch view' });
|
||||
const renameBtn = toolbar.getByRole('button', { name: 'Rename' });
|
||||
const renameInput = page.locator('.affine-attachment-rename-container input');
|
||||
@@ -110,7 +110,7 @@ function getAttachment(page: Page) {
|
||||
await assertRichImage(page, 1);
|
||||
},
|
||||
rename: async (newName: string) => {
|
||||
await attachment.hover();
|
||||
await attachment.click();
|
||||
await expect(toolbar).toBeVisible();
|
||||
await renameBtn.click();
|
||||
await page.keyboard.press(`${SHORT_KEY}+a`, { delay: 50 });
|
||||
@@ -207,7 +207,7 @@ test('should rename attachment works', async ({ page }) => {
|
||||
|
||||
expect(await getName()).toBe(FILE_NAME);
|
||||
|
||||
await attachment.hover();
|
||||
await attachment.click();
|
||||
await expect(renameBtn).toBeVisible();
|
||||
await renameBtn.click();
|
||||
await assertKeyboardWorkInInput(page, renameInput);
|
||||
@@ -225,20 +225,28 @@ test('should rename attachment works', async ({ page }) => {
|
||||
test('should turn attachment to image works', async ({ page }, testInfo) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
await initEmptyParagraphState(page);
|
||||
const { insertAttachment, waitLoading, turnToEmbed, turnImageToCard } =
|
||||
getAttachment(page);
|
||||
const {
|
||||
attachment,
|
||||
insertAttachment,
|
||||
waitLoading,
|
||||
turnToEmbed,
|
||||
turnImageToCard,
|
||||
} = getAttachment(page);
|
||||
|
||||
await focusRichText(page);
|
||||
await insertAttachment();
|
||||
// Wait for the attachment to be uploaded
|
||||
await waitLoading();
|
||||
|
||||
await attachment.click();
|
||||
await turnToEmbed();
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_1.json`
|
||||
);
|
||||
|
||||
await turnImageToCard();
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_2.json`
|
||||
);
|
||||
|
||||
@@ -237,7 +237,8 @@ test.describe('embed card toolbar', () => {
|
||||
await showEmbedCardToolbar(page);
|
||||
});
|
||||
|
||||
test('copy bookmark url by copy button', async ({ page }, testInfo) => {
|
||||
// TODO(@fundon): should move to affine side
|
||||
test.skip('copy bookmark url by copy button', async ({ page }, testInfo) => {
|
||||
await showEmbedCardToolbar(page);
|
||||
const { copyButton } = getEmbedCardToolbar(page);
|
||||
await copyButton.click();
|
||||
@@ -374,7 +375,7 @@ test.describe('embed youtube card', () => {
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
// change to card view
|
||||
const embedToolbar = page.locator('affine-embed-card-toolbar');
|
||||
const embedToolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(embedToolbar).toBeVisible();
|
||||
const embedView = page.locator('editor-menu-button', {
|
||||
hasText: 'embed view',
|
||||
@@ -429,7 +430,7 @@ test.describe('embed figma card', () => {
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
// change to card view
|
||||
const embedToolbar = page.locator('affine-embed-card-toolbar');
|
||||
const embedToolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(embedToolbar).toBeVisible();
|
||||
const embedView = page.locator('editor-menu-button', {
|
||||
hasText: 'embed view',
|
||||
|
||||
@@ -228,7 +228,7 @@ test('format quick bar should show up when double-clicking on text', async ({
|
||||
delay: 20,
|
||||
});
|
||||
await page.waitForTimeout(200);
|
||||
const formatBar = page.locator('.affine-format-bar-widget');
|
||||
const formatBar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(formatBar).toBeVisible();
|
||||
});
|
||||
|
||||
|
||||
@@ -30,13 +30,15 @@ test.describe('Embed synced doc', () => {
|
||||
);
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const referencePopup = page.locator('.affine-reference-popover-container');
|
||||
await expect(referencePopup).toBeVisible();
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const switchButton = page.getByRole('button', { name: 'Switch view' });
|
||||
const switchButton = toolbar.getByRole('button', { name: 'Switch view' });
|
||||
await switchButton.click();
|
||||
|
||||
const embedSyncedDocBtn = page.getByRole('button', { name: 'Embed view' });
|
||||
const embedSyncedDocBtn = toolbar.getByRole('button', {
|
||||
name: 'Embed view',
|
||||
});
|
||||
await expect(embedSyncedDocBtn).toBeVisible();
|
||||
|
||||
await embedSyncedDocBtn.click();
|
||||
@@ -70,7 +72,7 @@ test.describe('Embed synced doc', () => {
|
||||
);
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const toolbar = page.locator('.embed-card-toolbar');
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const switchBtn = toolbar.getByRole('button', { name: 'Switch view' });
|
||||
@@ -213,11 +215,13 @@ test.describe('Embed synced doc', () => {
|
||||
await initEmptyParagraphState(page);
|
||||
await focusRichText(page);
|
||||
await createAndConvertToEmbedSyncedDoc(page);
|
||||
|
||||
const locator = page.locator('affine-embed-synced-doc-block');
|
||||
await expect(locator).toBeVisible();
|
||||
await locator.click();
|
||||
|
||||
const toolbar = page.locator('editor-toolbar');
|
||||
const openMenu = toolbar.getByRole('button', { name: 'Open' });
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
const openMenu = toolbar.getByRole('button', { name: 'Open doc' });
|
||||
await openMenu.click();
|
||||
|
||||
const button = toolbar.getByRole('button', { name: 'Open this doc' });
|
||||
|
||||
@@ -60,7 +60,7 @@ test('should format quick bar show when select text', async ({ page }) => {
|
||||
}
|
||||
const rect = await getSelectionRect(page);
|
||||
assertAlmostEqual(box.x - rect.left, -98, 5);
|
||||
assertAlmostEqual(box.y - rect.bottom, 10, 5);
|
||||
assertAlmostEqual(box.y - rect.bottom, -133, 5);
|
||||
|
||||
// Click the edge of the format quick bar
|
||||
await page.mouse.click(box.x + 4, box.y + box.height / 2);
|
||||
@@ -247,17 +247,22 @@ test('should format quick bar be able to change background color', async ({
|
||||
|
||||
const { highlight } = getFormatBar(page);
|
||||
|
||||
await highlight.highlightBtn.hover();
|
||||
await highlight.highlightBtn.click();
|
||||
await expect(highlight.redForegroundBtn).toBeVisible();
|
||||
await expect(highlight.highlightBtn).toHaveAttribute(
|
||||
'data-last-used',
|
||||
'unset'
|
||||
);
|
||||
|
||||
// TODO(@fundon): these recent settings should be added to the dropdown menu.
|
||||
// await expect(highlight.highlightBtn).toHaveAttribute(
|
||||
// 'data-last-used',
|
||||
// 'unset'
|
||||
// );
|
||||
|
||||
await highlight.redForegroundBtn.click();
|
||||
await expect(highlight.highlightBtn).toHaveAttribute(
|
||||
'data-last-used',
|
||||
'var(--affine-text-highlight-foreground-red)'
|
||||
);
|
||||
|
||||
// TODO(@fundon): these recent settings should be added to the dropdown menu.
|
||||
// await expect(highlight.highlightBtn).toHaveAttribute(
|
||||
// 'data-last-used',
|
||||
// 'var(--affine-text-highlight-foreground-red)'
|
||||
// );
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_init.json`
|
||||
@@ -266,13 +271,17 @@ test('should format quick bar be able to change background color', async ({
|
||||
// select `123` paragraph by ctrl + a
|
||||
await focusRichText(page);
|
||||
await selectAllByKeyboard(page);
|
||||
// use last used color
|
||||
// // use last used color
|
||||
// await highlight.highlightBtn.click();
|
||||
|
||||
await highlight.highlightBtn.click();
|
||||
await highlight.redForegroundBtn.click();
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_select_all.json`
|
||||
);
|
||||
|
||||
await highlight.highlightBtn.click();
|
||||
await expect(highlight.defaultColorBtn).toBeVisible();
|
||||
await highlight.defaultColorBtn.click();
|
||||
|
||||
@@ -329,8 +338,6 @@ test('should format quick bar be able to link text', async ({
|
||||
`${testInfo.title}_init.json`
|
||||
);
|
||||
|
||||
// FIXME: remove this
|
||||
await focusRichText(page);
|
||||
await setSelection(page, 3, 0, 3, 3);
|
||||
// The link button should be active after click
|
||||
await expect(linkBtn).toHaveAttribute('active', '');
|
||||
@@ -352,24 +359,23 @@ test('should format quick bar be able to change to heading paragraph type', asyn
|
||||
// drag only the `456` paragraph
|
||||
await dragBetweenIndices(page, [0, 0], [0, 3]);
|
||||
|
||||
const { openParagraphMenu, h1Btn, bulletedBtn } = getFormatBar(page);
|
||||
await openParagraphMenu();
|
||||
const { openParagraphMenu, textBtn, h1Btn, bulletedBtn } = getFormatBar(page);
|
||||
|
||||
await expect(h1Btn).toBeVisible();
|
||||
await openParagraphMenu();
|
||||
await h1Btn.click();
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_init.json`
|
||||
);
|
||||
|
||||
await bulletedBtn.click();
|
||||
await openParagraphMenu();
|
||||
await bulletedBtn.click();
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_bulleted.json`
|
||||
);
|
||||
|
||||
const { textBtn } = getFormatBar(page);
|
||||
await openParagraphMenu();
|
||||
await textBtn.click();
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
@@ -485,7 +491,7 @@ test('should format quick bar position correct at the start of second line', asy
|
||||
}
|
||||
const selectionRect = await getSelectionRect(page);
|
||||
assertAlmostEqual(formatBox.x - selectionRect.x, -99, 5);
|
||||
assertAlmostEqual(formatBox.y + formatBox.height - selectionRect.top, 68, 5);
|
||||
assertAlmostEqual(formatBox.y + formatBox.height - selectionRect.top, -10, 5);
|
||||
});
|
||||
|
||||
test('should format quick bar action status updated while undo', async ({
|
||||
@@ -542,7 +548,7 @@ test('should format quick bar work in single block selection', async ({
|
||||
throw new Error('selectionRect is not found');
|
||||
}
|
||||
assertAlmostEqual(formatRect.x - selectionRect.x, 147.5, 10);
|
||||
assertAlmostEqual(formatRect.y - selectionRect.y, 33, 10);
|
||||
assertAlmostEqual(formatRect.y - selectionRect.y, -48, 10);
|
||||
|
||||
const boldBtn = formatBar.getByTestId('bold');
|
||||
await boldBtn.click();
|
||||
@@ -597,7 +603,7 @@ test('should format quick bar work in multiple block selection', async ({
|
||||
throw new Error('rect is not found');
|
||||
}
|
||||
assertAlmostEqual(box.x - rect.x, 147.5, 10);
|
||||
assertAlmostEqual(box.y - rect.y, 99, 10);
|
||||
assertAlmostEqual(box.y - rect.y, -48, 10);
|
||||
|
||||
await formatBarController.boldBtn.click();
|
||||
await formatBarController.italicBtn.click();
|
||||
@@ -647,7 +653,7 @@ test('should format quick bar with block selection works when update block type'
|
||||
`${testInfo.title}_init.json`
|
||||
);
|
||||
|
||||
await expect(formatBarController.formatBar).toBeVisible();
|
||||
await formatBarController.openParagraphMenu();
|
||||
await formatBarController.h1Btn.click();
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
`${testInfo.title}_final.json`
|
||||
|
||||
@@ -54,18 +54,18 @@ test('basic link', async ({ page }, testInfo) => {
|
||||
// clear text selection
|
||||
await page.keyboard.press('ArrowLeft');
|
||||
|
||||
const viewLinkPopoverLocator = page.locator('.affine-link-popover.view');
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
// Hover link
|
||||
await expect(viewLinkPopoverLocator).not.toBeVisible();
|
||||
await expect(toolbar).not.toBeVisible();
|
||||
await linkLocator.hover();
|
||||
// wait for popover delay open
|
||||
await page.waitForTimeout(200);
|
||||
await expect(viewLinkPopoverLocator).toBeVisible();
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
// Edit link
|
||||
const text2 = 'link2';
|
||||
const link2 = 'https://github.com';
|
||||
const editLinkBtn = viewLinkPopoverLocator.getByTestId('edit');
|
||||
const editLinkBtn = toolbar.getByTestId('edit');
|
||||
await editLinkBtn.click();
|
||||
|
||||
const editLinkPopoverLocator = page.locator('.affine-link-edit-popover');
|
||||
@@ -166,7 +166,7 @@ test('type character after link should not extend the link attributes', async ({
|
||||
);
|
||||
});
|
||||
|
||||
test('readonly mode should not trigger link popup', async ({ page }) => {
|
||||
test('readonly mode should not trigger toolbar', async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
const linkText = 'linkText';
|
||||
await createLinkBlock(page, 'linkText', 'http://example.com');
|
||||
@@ -174,9 +174,10 @@ test('readonly mode should not trigger link popup', async ({ page }) => {
|
||||
const linkLocator = page.locator(`text="${linkText}"`);
|
||||
|
||||
// Hover link
|
||||
const linkPopoverLocator = page.locator('.affine-link-popover');
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await linkLocator.hover();
|
||||
await expect(linkPopoverLocator).toBeVisible();
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await switchReadonly(page);
|
||||
|
||||
await page.mouse.move(0, 0);
|
||||
@@ -184,7 +185,7 @@ test('readonly mode should not trigger link popup', async ({ page }) => {
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
await linkLocator.hover();
|
||||
await expect(linkPopoverLocator).not.toBeVisible();
|
||||
await expect(toolbar).not.toBeVisible();
|
||||
|
||||
// ---
|
||||
// press hotkey should not trigger create link popup
|
||||
@@ -192,7 +193,7 @@ test('readonly mode should not trigger link popup', async ({ page }) => {
|
||||
await dragBetweenIndices(page, [0, 0], [0, 3]);
|
||||
await pressCreateLinkShortCut(page);
|
||||
|
||||
await expect(linkPopoverLocator).not.toBeVisible();
|
||||
await expect(toolbar).not.toBeVisible();
|
||||
const linkPopoverInput = page.locator('.affine-link-popover-input');
|
||||
await expect(linkPopoverInput).not.toBeVisible();
|
||||
});
|
||||
@@ -237,17 +238,16 @@ test('should keyboard work in link popover', async ({ page }) => {
|
||||
await assertKeyboardWorkInInput(page, linkPopoverInput);
|
||||
await page.mouse.click(500, 500);
|
||||
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
const linkLocator = page.locator(`text="${linkText}"`);
|
||||
const linkPopover = page.locator('.affine-link-popover');
|
||||
await linkLocator.hover();
|
||||
await waitNextFrame(page, 200);
|
||||
await expect(linkLocator).toBeVisible();
|
||||
// Hover link
|
||||
|
||||
// hover link
|
||||
await linkLocator.hover();
|
||||
// wait for popover delay open
|
||||
await page.waitForTimeout(200);
|
||||
await expect(linkPopover).toBeVisible();
|
||||
const editLinkBtn = linkPopover.getByTestId('edit');
|
||||
await page.waitForTimeout(500);
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const editLinkBtn = toolbar.getByTestId('edit');
|
||||
await editLinkBtn.click();
|
||||
|
||||
const editLinkPopover = page.locator('.affine-link-edit-popover');
|
||||
@@ -347,13 +347,12 @@ test('convert link to card', async ({ page }, testInfo) => {
|
||||
await setSelection(page, 3, 1, 3, 9);
|
||||
await pressCreateLinkShortCut(page);
|
||||
await waitNextFrame(page);
|
||||
const linkPopoverLocator = page.locator('.affine-link-popover');
|
||||
await expect(linkPopoverLocator).toBeVisible();
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
const linkPopoverInput = page.locator('.affine-link-popover-input');
|
||||
await expect(linkPopoverInput).toBeVisible();
|
||||
await type(page, link);
|
||||
await pressEnter(page);
|
||||
await expect(linkPopoverLocator).not.toBeVisible();
|
||||
await focusRichText(page, 1);
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
@@ -364,24 +363,24 @@ test('convert link to card', async ({ page }, testInfo) => {
|
||||
|
||||
await linkLocator.hover();
|
||||
await waitNextFrame(page);
|
||||
await expect(linkPopoverLocator).toBeVisible();
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Switch view' }).click();
|
||||
const linkToCardBtn = page.getByTestId('link-to-card');
|
||||
const linkToEmbedBtn = page.getByTestId('link-to-embed');
|
||||
await toolbar.getByRole('button', { name: 'Switch view' }).click();
|
||||
const linkToCardBtn = toolbar.getByTestId('link-to-card');
|
||||
const linkToEmbedBtn = toolbar.getByTestId('link-to-embed');
|
||||
await expect(linkToCardBtn).toBeVisible();
|
||||
await expect(linkToEmbedBtn).not.toBeVisible();
|
||||
|
||||
await page.mouse.move(0, 0);
|
||||
await waitNextFrame(page);
|
||||
await expect(linkPopoverLocator).not.toBeVisible();
|
||||
await expect(toolbar).not.toBeVisible();
|
||||
await focusRichText(page, 1);
|
||||
await pressTab(page);
|
||||
|
||||
await linkLocator.hover();
|
||||
await waitNextFrame(page);
|
||||
await expect(linkPopoverLocator).toBeVisible();
|
||||
await page.getByRole('button', { name: 'Switch view' }).click();
|
||||
await expect(toolbar).toBeVisible();
|
||||
await toolbar.getByRole('button', { name: 'Switch view' }).click();
|
||||
await expect(linkToCardBtn).toBeVisible();
|
||||
await expect(linkToEmbedBtn).not.toBeVisible();
|
||||
});
|
||||
@@ -400,13 +399,12 @@ test('convert link to embed', async ({ page }, testInfo) => {
|
||||
await setSelection(page, 3, 1, 3, 9);
|
||||
await pressCreateLinkShortCut(page);
|
||||
await waitNextFrame(page);
|
||||
const linkPopoverLocator = page.locator('.affine-link-popover');
|
||||
await expect(linkPopoverLocator).toBeVisible();
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
const linkPopoverInput = page.locator('.affine-link-popover-input');
|
||||
await expect(linkPopoverInput).toBeVisible();
|
||||
await type(page, link);
|
||||
await pressEnter(page);
|
||||
await expect(linkPopoverLocator).not.toBeVisible();
|
||||
await focusRichText(page);
|
||||
|
||||
expect(await getPageSnapshot(page, true)).toMatchSnapshot(
|
||||
@@ -417,5 +415,5 @@ test('convert link to embed', async ({ page }, testInfo) => {
|
||||
|
||||
await linkLocator.hover();
|
||||
await waitNextFrame(page);
|
||||
await expect(linkPopoverLocator).toBeVisible();
|
||||
await expect(toolbar).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -51,13 +51,13 @@ async function createAndConvertToEmbedLinkedDoc(page: Page) {
|
||||
);
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const referencePopup = page.locator('.affine-reference-popover-container');
|
||||
await expect(referencePopup).toBeVisible();
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const switchButton = page.getByRole('button', { name: 'Switch view' });
|
||||
const switchButton = toolbar.getByRole('button', { name: 'Switch view' });
|
||||
await switchButton.click();
|
||||
|
||||
const embedLinkedDocBtn = page.getByRole('button', { name: 'Card view' });
|
||||
const embedLinkedDocBtn = toolbar.getByRole('button', { name: 'Card view' });
|
||||
await expect(embedLinkedDocBtn).toBeVisible();
|
||||
await embedLinkedDocBtn.click();
|
||||
await waitNextFrame(page, 200);
|
||||
@@ -680,8 +680,9 @@ test('linked doc can be dragged from note to surface top level block', async ({
|
||||
await assertParentBlockFlavour(page, '9', 'affine:surface');
|
||||
});
|
||||
|
||||
// TODO(@fundon): should move to affine
|
||||
// Aliases
|
||||
test.describe('Customize linked doc title and description', () => {
|
||||
test.describe.skip('Customize linked doc title and description', () => {
|
||||
// Inline View
|
||||
test('should set a custom title for inline link', async ({ page }) => {
|
||||
await enterPlaygroundRoom(page);
|
||||
@@ -711,14 +712,14 @@ test.describe('Customize linked doc title and description', () => {
|
||||
await page0.hover();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const referencePopup = page.locator('.affine-reference-popover-container');
|
||||
await expect(referencePopup).toBeVisible();
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
const editButton = referencePopup.getByRole('button', { name: 'Edit' });
|
||||
const editButton = toolbar.getByRole('button', { name: 'Edit' });
|
||||
await editButton.click();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const popup = page.locator('.alias-form-popup');
|
||||
const popup = page.locator('reference-popup .popover-container');
|
||||
await expect(popup).toBeVisible();
|
||||
|
||||
const input = popup.locator('input');
|
||||
@@ -737,10 +738,10 @@ test.describe('Customize linked doc title and description', () => {
|
||||
await page0Alias.hover();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
await expect(referencePopup).toBeVisible();
|
||||
await expect(toolbar).toBeVisible();
|
||||
|
||||
// original title button
|
||||
const docTitle = referencePopup.getByRole('button', { name: 'Doc title' });
|
||||
const docTitle = toolbar.getByRole('button', { name: 'Doc title' });
|
||||
await expect(docTitle).toHaveText('title0', { useInnerText: true });
|
||||
|
||||
// reedit
|
||||
@@ -757,7 +758,7 @@ test.describe('Customize linked doc title and description', () => {
|
||||
await resetedPage0.hover();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
await expect(referencePopup).toBeVisible();
|
||||
await expect(toolbar).toBeVisible();
|
||||
await expect(docTitle).not.toBeVisible();
|
||||
});
|
||||
|
||||
@@ -786,9 +787,9 @@ test.describe('Customize linked doc title and description', () => {
|
||||
await page0.hover();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const referencePopup = page.locator('.affine-reference-popover-container');
|
||||
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
|
||||
let editButton = referencePopup.getByRole('button', { name: 'Edit' });
|
||||
let editButton = toolbar.getByRole('button', { name: 'Edit' });
|
||||
await editButton.click();
|
||||
|
||||
// title alias
|
||||
@@ -802,13 +803,13 @@ test.describe('Customize linked doc title and description', () => {
|
||||
await page0Alias.hover();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const switchButton = referencePopup.getByRole('button', {
|
||||
const switchButton = toolbar.getByRole('button', {
|
||||
name: 'Switch view',
|
||||
});
|
||||
await switchButton.click();
|
||||
|
||||
// switches to card view
|
||||
const toCardButton = referencePopup.getByRole('button', {
|
||||
const toCardButton = toolbar.getByRole('button', {
|
||||
name: 'Card view',
|
||||
});
|
||||
await toCardButton.click();
|
||||
@@ -825,13 +826,12 @@ test.describe('Customize linked doc title and description', () => {
|
||||
await linkedDocBlock.click();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
const cardToolbar = page.locator('affine-embed-card-toolbar');
|
||||
const docTitleButton = cardToolbar.getByRole('button', {
|
||||
const docTitleButton = toolbar.getByRole('button', {
|
||||
name: 'Doc title',
|
||||
});
|
||||
await expect(docTitleButton).toBeVisible();
|
||||
|
||||
editButton = cardToolbar.getByRole('button', { name: 'Edit' });
|
||||
editButton = toolbar.getByRole('button', { name: 'Edit' });
|
||||
await editButton.click();
|
||||
|
||||
await waitNextFrame(page, 200);
|
||||
|
||||
@@ -28,6 +28,8 @@ test('should only show one format bar when multiple editors are toggled', async
|
||||
await dragBetweenCoords(page, above123, bottomRight789, { steps: 10 });
|
||||
|
||||
// should only show one format bar
|
||||
const formatBar = page.locator('.affine-format-bar-widget');
|
||||
const formatBar = page.locator(
|
||||
'affine-toolbar-widget editor-toolbar[data-open]'
|
||||
);
|
||||
await expect(formatBar).toHaveCount(1);
|
||||
});
|
||||
|
||||
@@ -202,7 +202,9 @@ export async function dragBlockToPoint(
|
||||
|
||||
export async function moveToImage(page: Page) {
|
||||
const { x, y } = await page.evaluate(() => {
|
||||
const bottomRightButton = document.querySelector('img') as HTMLElement;
|
||||
const bottomRightButton = document.querySelector(
|
||||
'affine-image img'
|
||||
) as HTMLElement;
|
||||
const imageClient = bottomRightButton.getBoundingClientRect();
|
||||
const y = imageClient.top;
|
||||
return {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { waitNextFrame } from './actions/misc.js';
|
||||
import { assertAlmostEqual } from './asserts.js';
|
||||
|
||||
export function getFormatBar(page: Page) {
|
||||
const formatBar = page.locator('.affine-format-bar-widget');
|
||||
const formatBar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
const boldBtn = formatBar.getByTestId('bold');
|
||||
const italicBtn = formatBar.getByTestId('italic');
|
||||
const underlineBtn = formatBar.getByTestId('underline');
|
||||
@@ -12,28 +12,26 @@ export function getFormatBar(page: Page) {
|
||||
const codeBtn = formatBar.getByTestId('code');
|
||||
const linkBtn = formatBar.getByTestId('link');
|
||||
// highlight
|
||||
const highlightBtn = formatBar.locator('.highlight-icon');
|
||||
const redForegroundBtn = formatBar.getByTestId(
|
||||
'var(--affine-text-highlight-foreground-red)'
|
||||
);
|
||||
const highlightBtn = formatBar.getByRole('button', { name: 'highlight' });
|
||||
const redForegroundBtn = formatBar.getByTestId('foreground-red');
|
||||
const createLinkedDocBtn = formatBar.getByTestId('convert-to-linked-doc');
|
||||
const defaultColorBtn = formatBar.getByTestId('unset');
|
||||
const defaultColorBtn = formatBar.getByTestId('foreground-default');
|
||||
const highlight = {
|
||||
highlightBtn,
|
||||
redForegroundBtn,
|
||||
defaultColorBtn,
|
||||
};
|
||||
|
||||
const paragraphBtn = formatBar.locator(`.paragraph-button`);
|
||||
const paragraphBtn = formatBar.getByRole('button', { name: 'Conversions' });
|
||||
const openParagraphMenu = async () => {
|
||||
await expect(formatBar).toBeVisible();
|
||||
await paragraphBtn.hover();
|
||||
await paragraphBtn.click();
|
||||
};
|
||||
|
||||
const textBtn = formatBar.getByTestId('affine:paragraph/text');
|
||||
const h1Btn = formatBar.getByTestId('affine:paragraph/h1');
|
||||
const bulletedBtn = formatBar.getByTestId('affine:list/bulleted');
|
||||
const codeBlockBtn = formatBar.getByTestId('affine:code/');
|
||||
const textBtn = formatBar.getByRole('button', { name: 'Text' });
|
||||
const h1Btn = formatBar.getByRole('button', { name: 'Heading 1' });
|
||||
const bulletedBtn = formatBar.getByRole('button', { name: 'Bulleted List' });
|
||||
const codeBlockBtn = formatBar.getByRole('button', { name: 'Code Block' });
|
||||
|
||||
const moreBtn = formatBar.getByRole('button', { name: 'More' });
|
||||
const copyBtn = formatBar.getByRole('button', { name: 'Copy' });
|
||||
@@ -81,11 +79,11 @@ export function getFormatBar(page: Page) {
|
||||
}
|
||||
|
||||
export function getEmbedCardToolbar(page: Page) {
|
||||
const embedCardToolbar = page.locator('.embed-card-toolbar');
|
||||
const embedCardToolbar = page.locator('affine-toolbar-widget editor-toolbar');
|
||||
function createButtonLocator(name: string) {
|
||||
return embedCardToolbar.getByRole('button', { name });
|
||||
}
|
||||
const copyButton = createButtonLocator('copy');
|
||||
const copyButton = createButtonLocator('copy-link');
|
||||
const editButton = createButtonLocator('edit');
|
||||
const cardStyleButton = createButtonLocator('card style');
|
||||
const captionButton = createButtonLocator('caption');
|
||||
|
||||
Reference in New Issue
Block a user