From 8f144e9de87c17d6a665bc3be453feb3ee097bee Mon Sep 17 00:00:00 2001 From: fundon Date: Thu, 26 Dec 2024 12:32:11 +0000 Subject: [PATCH] fix(component): fix lit portal not re-rendering in inline links case (#9321) * uses `portal.key` in templates * updates `portal.id` for use in queries --- .../src/components/options.ts | 1 + .../src/lit-react/lit-portal/lite-portal.tsx | 25 +-- .../pdf-viewer-embedded-inner.tsx | 11 +- .../bi-directional-link-panel.tsx | 2 +- .../block-suite-editor/lit-adaper.tsx | 2 +- .../e2e/attachment-preview.spec.ts | 159 +++++++++++++++++- 6 files changed, 175 insertions(+), 25 deletions(-) diff --git a/blocksuite/affine/block-attachment/src/components/options.ts b/blocksuite/affine/block-attachment/src/components/options.ts index 9dc581f0f0c75..6bad4088d5e19 100644 --- a/blocksuite/affine/block-attachment/src/components/options.ts +++ b/blocksuite/affine/block-attachment/src/components/options.ts @@ -98,6 +98,7 @@ export function attachmentViewToggleMenu({ button => button.type, ({ type, label, action, disabled }) => html` void; export function createLitPortalAnchor(callback: (event: PortalEvent) => void) { - const id = nanoid(); return html``; } @@ -119,24 +118,26 @@ export const useLitPortalFactory = () => { } const prevId = event.previousPortalId; - // Ignore first `willUpdate` - if (!prevId) { - return; - } - // No re-rendering allowed - // Used in `pdf embed view` scenario - if (!rerendering) { + // Ignores first `willUpdate` + if (!prevId) { return; } setPortals(portals => { const portal = portals.find(p => p.id === prevId); - if (!portal) return portals; + if (!portal) return [...portals]; + // Updates `ID` portal.id = id; - portal.portal.key = id; - portal.portal.children = element; + + // Re-rendering + // true: `inline link` + // false: `pdf embed view` + if (rerendering) { + portal.portal = ReactDOM.createPortal(element, target, id); + } + return [...portals]; }); }); diff --git a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx index 660b13dcb39db..b43d93bec3f0c 100644 --- a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx +++ b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx @@ -221,6 +221,7 @@ export function PDFViewerEmbeddedInner({ model }: PDFViewerEmbeddedInnerProps) { icon={} className={embeddedStyles.pdfControlButton} onDoubleClick={stopPropagation} + aria-label="Prev" {...navigator.prev} /> } className={embeddedStyles.pdfControlButton} onDoubleClick={stopPropagation} + aria-label="Next" {...navigator.next} /> - {meta.pageCount > 0 ? cursor + 1 : '-'}/ - {meta.pageCount > 0 ? meta.pageCount : '-'} + + {meta.pageCount > 0 ? cursor + 1 : '-'} + + / + + {meta.pageCount > 0 ? meta.pageCount : '-'} + diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/bi-directional-link-panel.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/bi-directional-link-panel.tsx index 9225fa6fac65f..e45e5b7875dd1 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/bi-directional-link-panel.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/bi-directional-link-panel.tsx @@ -357,7 +357,7 @@ export const BiDirectionalLinkPanel = () => { { <> {portals.map(p => ( - {p.portal} + {p.portal} ))} } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx index 0da7345fdfd93..f9fd1acff59fc 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx @@ -194,7 +194,7 @@ const usePatchSpecs = (shared: boolean, mode: DocMode) => { () => ( <> {portals.map(p => ( - {p.portal} + {p.portal} ))} ), diff --git a/tests/affine-local/e2e/attachment-preview.spec.ts b/tests/affine-local/e2e/attachment-preview.spec.ts index 8b3ddf2528e07..9710cbc38773e 100644 --- a/tests/affine-local/e2e/attachment-preview.spec.ts +++ b/tests/affine-local/e2e/attachment-preview.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable unicorn/prefer-dom-node-dataset */ import path from 'node:path'; import { test } from '@affine-test/kit/playwright'; @@ -7,7 +6,13 @@ import { clickNewPageButton, getBlockSuiteEditorTitle, waitForEditorLoad, + waitForEmptyEditor, } from '@affine-test/kit/utils/page-logic'; +import { + confirmExperimentalPrompt, + openEditorSetting, + openExperimentalFeaturesPanel, +} from '@affine-test/kit/utils/setting'; import type { Page } from '@playwright/test'; import { expect } from '@playwright/test'; @@ -53,10 +58,10 @@ test('attachment preview should be shown', async ({ page }) => { await page.waitForTimeout(500); - const pageCount = attachmentViewer.locator('.page-cursor'); - expect(await pageCount.textContent()).toBe('1'); - const pageTotal = attachmentViewer.locator('.page-count'); - expect(await pageTotal.textContent()).toBe('3'); + const pageCursor = attachmentViewer.locator('.page-cursor'); + expect(await pageCursor.textContent()).toBe('1'); + const pageCount = attachmentViewer.locator('.page-count'); + expect(await pageCount.textContent()).toBe('3'); const thumbnails = attachmentViewer.locator('.thumbnails'); await thumbnails.locator('button').click(); @@ -99,10 +104,10 @@ test('attachment preview can be expanded', async ({ page }) => { await page.waitForTimeout(500); - const pageCount = attachmentViewer.locator('.page-cursor'); - expect(await pageCount.textContent()).toBe('1'); - const pageTotal = attachmentViewer.locator('.page-count'); - expect(await pageTotal.textContent()).toBe('3'); + const pageCursor = attachmentViewer.locator('.page-cursor'); + expect(await pageCursor.textContent()).toBe('1'); + const pageCount = attachmentViewer.locator('.page-count'); + expect(await pageCount.textContent()).toBe('3'); const thumbnails = attachmentViewer.locator('.thumbnails'); await thumbnails.locator('button').click(); @@ -116,3 +121,139 @@ test('attachment preview can be expanded', async ({ page }) => { .count() ).toBe(3); }); + +test('should preview PDF in embed view', async ({ page }) => { + await openHomePage(page); + await clickNewPageButton(page); + await waitForEmptyEditor(page); + + const title = getBlockSuiteEditorTitle(page); + await title.click(); + await page.keyboard.type('PDF preview'); + + // Opens settings panel + await openEditorSetting(page); + await openExperimentalFeaturesPanel(page); + await confirmExperimentalPrompt(page); + + const settingModal = page.locator('[data-testid=setting-modal-content]'); + const item = settingModal.locator('div').getByText('PDF embed preview'); + await item.waitFor({ state: 'attached' }); + await expect(item).toBeVisible(); + const button = item.locator('label'); + const isChecked = await button.locator('input').isChecked(); + if (!isChecked) { + await button.click(); + } + + // Closes settings panel + await page.keyboard.press('Escape'); + + await clickNewPageButton(page); + await waitForEmptyEditor(page); + + await title.click(); + await page.keyboard.type('PDF page'); + + await page.keyboard.press('Enter'); + + await insertAttachment( + page, + path.join(__dirname, '../../fixtures/lorem-ipsum.pdf') + ); + + const attachment = page.locator('affine-attachment'); + await attachment.hover(); + + const attachmentToolbar = page.locator('.affine-attachment-toolbar'); + await expect(attachmentToolbar).toBeVisible(); + + // Switches to embed view + await attachmentToolbar.getByRole('button', { name: 'Switch view' }).click(); + await attachmentToolbar.getByRole('button', { name: 'Embed view' }).click(); + + await page.waitForTimeout(500); + + const portal = attachment.locator('lit-react-portal'); + await expect(portal).toBeVisible(); + + await attachment.click(); + + await page.waitForTimeout(500); + + const pageCursor = portal.locator('.page-cursor'); + expect(await pageCursor.textContent()).toBe('1'); + const pageCount = portal.locator('.page-count'); + expect(await pageCount.textContent()).toBe('3'); + + const prevButton = portal.getByRole('button', { name: 'Prev' }); + const nextButton = portal.getByRole('button', { name: 'Next' }); + + await nextButton.click(); + expect(await pageCursor.textContent()).toBe('2'); + + await nextButton.click(); + expect(await pageCursor.textContent()).toBe('3'); + + await prevButton.click(); + expect(await pageCursor.textContent()).toBe('2'); + + // Title alias + { + await page.keyboard.press('Enter'); + + await page.keyboard.press('@'); + + const doc0 = page.locator('.linked-doc-popover').getByText('PDF preview'); + await doc0.click(); + + await page.keyboard.press('@'); + + const doc1 = page.locator('.linked-doc-popover').getByText('PDF page'); + await doc1.click(); + + const inlineLink = page.locator('affine-reference').nth(0); + const inlineToolbar = page.locator('reference-popup'); + const inlineTitle = inlineLink.locator('.affine-reference-title'); + + await expect(inlineTitle).toHaveText('PDF preview'); + + const bouding = await inlineLink.boundingBox(); + expect(bouding).not.toBeNull(); + + await page.mouse.move(bouding!.x - 50, bouding!.y + bouding!.height / 2); + await page.waitForTimeout(500); + await page.mouse.click(bouding!.x - 50, bouding!.y + bouding!.height / 2); + + await inlineLink.hover({ timeout: 500 }); + + // Edits title + await inlineToolbar.getByRole('button', { name: 'Edit' }).click(); + + // Title alias + await page.keyboard.type('PDF embed preview'); + await page.keyboard.press('Enter'); + + await expect(inlineTitle).toHaveText('PDF embed preview'); + } + + // PDF embed view should not be re-rendered + expect(await pageCursor.textContent()).toBe('2'); + expect(await pageCount.textContent()).toBe('3'); + + // Chagnes origin title + { + const inlineLink = page.locator('affine-reference').nth(1); + const inlineTitle = inlineLink.locator('.affine-reference-title'); + await expect(inlineTitle).toHaveText('PDF page'); + + await title.click(); + await page.keyboard.type(' preview'); + + await expect(inlineTitle).toHaveText('PDF page preview'); + } + + // PDF embed view should not be re-rendered + expect(await pageCursor.textContent()).toBe('2'); + expect(await pageCount.textContent()).toBe('3'); +});