diff --git a/.eslintrc.js b/.eslintrc.js index 227bcac1d0..c96058a4ed 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -247,7 +247,8 @@ const config = { 'react-hooks/exhaustive-deps': [ 'warn', { - additionalHooks: '(useAsyncCallback|useDraggable|useDropTarget)', + additionalHooks: + '(useAsyncCallback|useCatchEventCallback|useDraggable|useDropTarget)', }, ], }, diff --git a/packages/frontend/core/src/components/affine/reference-link/index.tsx b/packages/frontend/core/src/components/affine/reference-link/index.tsx index ec146a10ff..66921a0a0c 100644 --- a/packages/frontend/core/src/components/affine/reference-link/index.tsx +++ b/packages/frontend/core/src/components/affine/reference-link/index.tsx @@ -106,7 +106,6 @@ export function AffinePageReference({ e.preventDefault(); e.stopPropagation(); peekView.open(ref.current).catch(console.error); - return false; // means this click is handled } if (isInPeekView) { peekView.close(); diff --git a/packages/frontend/core/src/components/app-sidebar/add-page-button/index.tsx b/packages/frontend/core/src/components/app-sidebar/add-page-button/index.tsx index 369c623d0f..ff2e756acc 100644 --- a/packages/frontend/core/src/components/app-sidebar/add-page-button/index.tsx +++ b/packages/frontend/core/src/components/app-sidebar/add-page-button/index.tsx @@ -29,6 +29,7 @@ export function AddPageButton({ style={style} className={clsx([styles.root, className])} onClick={onClick} + onAuxClick={onClick} > diff --git a/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx b/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx index 2282d85694..c9a5f95dfa 100644 --- a/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx +++ b/packages/frontend/core/src/components/page-list/collections/collection-list-item.tsx @@ -1,13 +1,14 @@ import { Checkbox, useDraggable } from '@affine/component'; import { WorkbenchLink } from '@affine/core/modules/workbench'; import type { AffineDNDData } from '@affine/core/types/dnd'; +import { stopPropagation } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import type { ForwardedRef, PropsWithChildren } from 'react'; import { forwardRef, useCallback, useMemo } from 'react'; import { selectionStateAtom, useAtom } from '../scoped-atoms'; import type { CollectionListItemProps, PageListItemProps } from '../types'; -import { ColWrapper, stopPropagation } from '../utils'; +import { ColWrapper } from '../utils'; import * as styles from './collection-list-item.css'; const ListTitleCell = ({ diff --git a/packages/frontend/core/src/components/page-list/components/new-page-button.tsx b/packages/frontend/core/src/components/page-list/components/new-page-button.tsx index 05a026e79b..0c909b80e4 100644 --- a/packages/frontend/core/src/components/page-list/components/new-page-button.tsx +++ b/packages/frontend/core/src/components/page-list/components/new-page-button.tsx @@ -35,6 +35,7 @@ export const CreateNewPagePopup = ({ desc={t['com.affine.write_with_a_blank_page']()} right={} onClick={createNewPage} + onAuxClick={createNewPage} data-testid="new-page-button-in-all-page" /> } onClick={createNewEdgeless} + onAuxClick={createNewEdgeless} data-testid="new-edgeless-button-in-all-page" /> {importFile ? ( @@ -117,6 +119,7 @@ export const NewPageButton = ({ setOpen(open => !open), [])} > {children} diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx index 4a0929dba3..564671d022 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx @@ -10,6 +10,7 @@ import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; import { track } from '@affine/core/mixpanel'; import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; +import { isNewTabTrigger } from '@affine/core/utils'; import type { Collection } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; import { @@ -66,12 +67,9 @@ export const PageListHeader = () => { size="small" testId="new-page-button-trigger" onCreateEdgeless={e => - // todo: abstract this for ctrl check - createEdgeless(e?.metaKey || e?.ctrlKey ? 'new-tab' : true) - } - onCreatePage={e => - createPage(e?.metaKey || e?.ctrlKey ? 'new-tab' : true) + createEdgeless(isNewTabTrigger(e) ? 'new-tab' : true) } + onCreatePage={e => createPage(isNewTabTrigger(e) ? 'new-tab' : true)} onImportFile={onImportFile} >
{t['New Page']()}
diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-item.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-item.tsx index 9b93cca417..2675a47f3f 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-list-item.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-list-item.tsx @@ -1,6 +1,7 @@ import { Checkbox, Tooltip, useDraggable } from '@affine/component'; import { TagService } from '@affine/core/modules/tag'; import type { AffineDNDData } from '@affine/core/types/dnd'; +import { stopPropagation } from '@affine/core/utils'; import { i18nTime } from '@affine/i18n'; import { useLiveData, useService } from '@toeverything/infra'; import type { ForwardedRef, PropsWithChildren } from 'react'; @@ -15,7 +16,7 @@ import { } from '../scoped-atoms'; import type { PageListItemProps } from '../types'; import { useAllDocDisplayProperties } from '../use-all-doc-display-properties'; -import { ColWrapper, stopPropagation } from '../utils'; +import { ColWrapper } from '../utils'; import * as styles from './page-list-item.css'; import { PageTags } from './page-tags'; @@ -310,18 +311,18 @@ const PageListItemWrapper = forwardRef( if (!selectionState.selectable) { return; } - stopPropagation(e); + e.stopPropagation(); const currentIndex = pageIds.indexOf(pageId); if (e.shiftKey) { + e.preventDefault(); if (!selectionState.selectionActive) { setSelectionActive(true); setAnchorIndex(currentIndex); onClick?.(); - return false; + } else { + handleShiftClick(currentIndex); } - handleShiftClick(currentIndex); - return false; } else { setAnchorIndex(undefined); setRangeIds([]); diff --git a/packages/frontend/core/src/components/page-list/docs/page-tags.tsx b/packages/frontend/core/src/components/page-list/docs/page-tags.tsx index a903a32dac..e064248cd6 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-tags.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-tags.tsx @@ -1,13 +1,13 @@ import { Menu } from '@affine/component'; import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook'; import type { Tag } from '@affine/core/modules/tag'; +import { stopPropagation } from '@affine/core/utils'; import { CloseIcon, MoreHorizontalIcon } from '@blocksuite/icons/rc'; import { LiveData, useLiveData } from '@toeverything/infra'; import { assignInlineVars } from '@vanilla-extract/dynamic'; import clsx from 'clsx'; import { useMemo } from 'react'; -import { stopPropagation } from '../utils'; import * as styles from './page-tags.css'; export interface PageTagsProps { diff --git a/packages/frontend/core/src/components/page-list/operation-cell.tsx b/packages/frontend/core/src/components/page-list/operation-cell.tsx index 48078a3fd2..a61c7a5ed0 100644 --- a/packages/frontend/core/src/components/page-list/operation-cell.tsx +++ b/packages/frontend/core/src/components/page-list/operation-cell.tsx @@ -9,6 +9,7 @@ import { import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper'; import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper'; +import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook'; import { track } from '@affine/core/mixpanel'; import { FavoriteService } from '@affine/core/modules/favorite'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; @@ -277,18 +278,30 @@ export const TrashOperationCell = ({ const t = useI18n(); const { openConfirmModal } = useConfirmModal(); - const onConfirmPermanentlyDelete = useCallback(() => { - openConfirmModal({ - title: `${t['com.affine.trashOperation.deletePermanently']()}?`, - description: t['com.affine.trashOperation.deleteDescription'](), - cancelText: t['Cancel'](), - confirmText: t['com.affine.trashOperation.delete'](), - confirmButtonOptions: { - variant: 'error', - }, - onConfirm: onPermanentlyDeletePage, - }); - }, [onPermanentlyDeletePage, openConfirmModal, t]); + const onConfirmPermanentlyDelete = useCatchEventCallback( + e => { + e.preventDefault(); + openConfirmModal({ + title: `${t['com.affine.trashOperation.deletePermanently']()}?`, + description: t['com.affine.trashOperation.deleteDescription'](), + cancelText: t['Cancel'](), + confirmText: t['com.affine.trashOperation.delete'](), + confirmButtonOptions: { + variant: 'error', + }, + onConfirm: onPermanentlyDeletePage, + }); + }, + [onPermanentlyDeletePage, openConfirmModal, t] + ); + + const handleRestorePage = useCatchEventCallback( + e => { + e.preventDefault(); + onRestorePage(); + }, + [onRestorePage] + ); return ( @@ -297,9 +310,7 @@ export const TrashOperationCell = ({ tooltipOptions={tooltipSideTop} data-testid="restore-page-button" style={{ marginRight: '12px' }} - onClick={() => { - onRestorePage(); - }} + onClick={handleRestorePage} size="20" > diff --git a/packages/frontend/core/src/components/page-list/page-header.tsx b/packages/frontend/core/src/components/page-list/page-header.tsx index 84bee49bb0..562ef57156 100644 --- a/packages/frontend/core/src/components/page-list/page-header.tsx +++ b/packages/frontend/core/src/components/page-list/page-header.tsx @@ -1,5 +1,6 @@ import type { CheckboxProps } from '@affine/component'; import { Checkbox } from '@affine/component'; +import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook'; import { useI18n } from '@affine/i18n'; import { MultiSelectIcon } from '@blocksuite/icons/rc'; import clsx from 'clsx'; @@ -19,7 +20,6 @@ import { useAtomValue, } from './scoped-atoms'; import type { HeaderColDef, ListItem } from './types'; -import { stopPropagation } from './utils'; // the checkbox on the header has three states: // when list selectable = true, the checkbox will be presented @@ -28,23 +28,19 @@ import { stopPropagation } from './utils'; const ListHeaderCheckbox = () => { const [selectionState, setSelectionState] = useAtom(selectionStateAtom); const items = useAtomValue(itemsAtom); - const onActivateSelection: MouseEventHandler = useCallback( - e => { - stopPropagation(e); - setSelectionState(true); - }, - [setSelectionState] - ); + const onActivateSelection: MouseEventHandler = useCatchEventCallback(() => { + setSelectionState(true); + }, [setSelectionState]); const handlers = useAtomValue(listHandlersAtom); - const onChange: NonNullable = useCallback( - (e, checked) => { - stopPropagation(e); - handlers.onSelectedIdsChange?.( - checked ? (items ?? []).map(i => i.id) : [] - ); - }, - [handlers, items] - ); + const onChange: NonNullable = + useCatchEventCallback( + (_e, checked) => { + handlers.onSelectedIdsChange?.( + checked ? (items ?? []).map(i => i.id) : [] + ); + }, + [handlers, items] + ); if (!selectionState.selectable) { return null; diff --git a/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx b/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx index 92b3c0ec07..7cc6c84a68 100644 --- a/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx +++ b/packages/frontend/core/src/components/page-list/tags/tag-list-item.tsx @@ -1,13 +1,14 @@ import { Checkbox, useDraggable } from '@affine/component'; import { WorkbenchLink } from '@affine/core/modules/workbench'; import type { AffineDNDData } from '@affine/core/types/dnd'; +import { stopPropagation } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import type { ForwardedRef, PropsWithChildren } from 'react'; import { forwardRef, useCallback, useMemo } from 'react'; import { selectionStateAtom, useAtom } from '../scoped-atoms'; import type { TagListItemProps } from '../types'; -import { ColWrapper, stopPropagation } from '../utils'; +import { ColWrapper } from '../utils'; import * as styles from './tag-list-item.css'; const TagListTitleCell = ({ diff --git a/packages/frontend/core/src/components/page-list/utils.tsx b/packages/frontend/core/src/components/page-list/utils.tsx index f91ce95054..1a63f2fe36 100644 --- a/packages/frontend/core/src/components/page-list/utils.tsx +++ b/packages/frontend/core/src/components/page-list/utils.tsx @@ -1,5 +1,4 @@ import clsx from 'clsx'; -import type { BaseSyntheticEvent } from 'react'; import { forwardRef } from 'react'; import * as styles from './list.css'; @@ -58,14 +57,6 @@ export const betweenDaysAgo = ( return !withinDaysAgo(date, days0) && withinDaysAgo(date, days1); }; -export function stopPropagation(event: BaseSyntheticEvent) { - event.stopPropagation(); - event.preventDefault(); -} -export function stopPropagationWithoutPrevent(event: BaseSyntheticEvent) { - event.stopPropagation(); -} - // credit: https://github.com/facebook/fbjs/blob/main/packages/fbjs/src/core/shallowEqual.js export function shallowEqual(objA: any, objB: any) { if (Object.is(objA, objB)) { diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index 1203e99c96..214bb0fb3f 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -9,6 +9,7 @@ import { } from '@affine/core/modules/explorer'; import { ExplorerTags } from '@affine/core/modules/explorer/views/sections/tags'; import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/services/cmdk'; +import { isNewTabTrigger } from '@affine/core/utils'; import { events } from '@affine/electron-api'; import { useI18n } from '@affine/i18n'; import { AllDocsIcon, SettingsIcon } from '@blocksuite/icons/rc'; @@ -85,9 +86,7 @@ export const RootAppSidebar = (): ReactElement => { const onClickNewPage = useAsyncCallback( async (e?: MouseEvent) => { - const page = pageHelper.createPage( - e?.ctrlKey || e?.metaKey ? 'new-tab' : true - ); + const page = pageHelper.createPage(isNewTabTrigger(e) ? 'new-tab' : true); page.load(); track.$.navigationPanel.$.createDoc(); }, diff --git a/packages/frontend/core/src/components/root-app-sidebar/journal-button.tsx b/packages/frontend/core/src/components/root-app-sidebar/journal-button.tsx index 514903100e..37f3fc5346 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/journal-button.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/journal-button.tsx @@ -1,13 +1,15 @@ +import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook'; import { useJournalInfoHelper, useJournalRouteHelper, } from '@affine/core/hooks/use-journal'; import { WorkbenchService } from '@affine/core/modules/workbench'; import type { DocCollection } from '@affine/core/shared'; +import { isNewTabTrigger } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { TodayIcon, TomorrowIcon, YesterdayIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; -import { type MouseEvent, useCallback } from 'react'; +import { type MouseEvent } from 'react'; import { MenuItem } from '../app-sidebar'; @@ -27,9 +29,9 @@ export const AppSidebarJournalButton = ({ location.pathname.split('/')[1] ); - const handleOpenToday = useCallback( + const handleOpenToday = useCatchEventCallback( (e: MouseEvent) => { - openToday(e.ctrlKey || e.metaKey); + openToday(isNewTabTrigger(e)); }, [openToday] ); @@ -48,6 +50,7 @@ export const AppSidebarJournalButton = ({ data-testid="slider-bar-journals-button" active={isJournal} onClick={handleOpenToday} + onAuxClick={handleOpenToday} icon={} > {t['com.affine.journal.app-sidebar-title']()} diff --git a/packages/frontend/core/src/hooks/use-catch-event-hook.ts b/packages/frontend/core/src/hooks/use-catch-event-hook.ts index 0d71f4ddbe..3040e72ce9 100644 --- a/packages/frontend/core/src/hooks/use-catch-event-hook.ts +++ b/packages/frontend/core/src/hooks/use-catch-event-hook.ts @@ -2,14 +2,17 @@ import { type DependencyList, type SyntheticEvent } from 'react'; import { useAsyncCallback } from './affine-async-hooks'; -export const useCatchEventCallback = ( - cb: (e: E) => void | Promise, +export const useCatchEventCallback = < + E extends SyntheticEvent, + Args extends any[], +>( + cb: (e: E, ...args: Args) => void | Promise, deps: DependencyList ) => { return useAsyncCallback( - async (e: E) => { + async (e: E, ...args: Args) => { e.stopPropagation(); - await cb(e); + await cb(e, ...args); }, // eslint-disable-next-line react-hooks/exhaustive-deps deps diff --git a/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx index eeea7ef3f9..f59ebe3f3d 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx @@ -15,6 +15,7 @@ import { } from '@affine/core/modules/favorite'; import { WorkbenchService } from '@affine/core/modules/workbench'; import type { AffineDNDData } from '@affine/core/types/dnd'; +import { isNewTabTrigger } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { PlusIcon } from '@blocksuite/icons/rc'; import { DocsService, useLiveData, useServices } from '@toeverything/infra'; @@ -81,7 +82,7 @@ export const ExplorerFavorites = () => { favoriteService.favoriteList.indexAt('before') ); workbenchService.workbench.openDoc(newDoc.id, { - at: e.ctrlKey || e.metaKey ? 'new-tab' : 'active', + at: isNewTabTrigger(e) ? 'new-tab' : 'active', }); explorerSection.setCollapsed(false); }, @@ -173,6 +174,7 @@ export const ExplorerFavorites = () => { data-event-props="$.navigationPanel.favorites.createDoc" data-event-args-control="addFavorite" onClick={handleCreateNewFavoriteDoc} + onAuxClick={handleCreateNewFavoriteDoc} size="16" tooltip={t[ 'com.affine.rootAppSidebar.explorer.fav-section-add-tooltip' diff --git a/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx b/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx index 16eec059de..0287a56cda 100644 --- a/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx +++ b/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx @@ -1,5 +1,6 @@ import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useCatchEventCallback } from '@affine/core/hooks/use-catch-event-hook'; +import { isNewTabTrigger } from '@affine/core/utils'; import { useLiveData, useService } from '@toeverything/infra'; import { type To } from 'history'; import { forwardRef, type MouseEvent } from 'react'; @@ -11,7 +12,7 @@ export const WorkbenchLink = forwardRef< React.PropsWithChildren< { to: To; - onClick?: (e: MouseEvent) => boolean | void; // return false to stop propagation + onClick?: (e: MouseEvent) => void; } & React.HTMLProps > >(function WorkbenchLink({ to, onClick, ...other }, ref) { @@ -23,26 +24,33 @@ export const WorkbenchLink = forwardRef< (typeof to === 'string' ? to : `${to.pathname}${to.search}${to.hash}`); const handleClick = useCatchEventCallback( async (event: React.MouseEvent) => { - event.preventDefault(); - if (onClick?.(event) === false) { + onClick?.(event); + if (event.defaultPrevented) { return; } - const at = (() => { - if (event.ctrlKey || event.metaKey) { + if (isNewTabTrigger(event)) { return event.altKey && appSettings.enableMultiView ? 'tail' : 'new-tab'; } return 'active'; })(); - workbench.open(to, { at }); + event.preventDefault(); }, [appSettings.enableMultiView, onClick, to, workbench] ); // eslint suspicious runtime error // eslint-disable-next-line react/no-danger-with-children - return ; + return ( + + ); }); diff --git a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx index 61be4cd4f0..5a215384a8 100644 --- a/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx +++ b/packages/frontend/core/src/pages/workspace/all-page/all-page-header.tsx @@ -8,6 +8,7 @@ import { Header } from '@affine/core/components/pure/header'; import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { track } from '@affine/core/mixpanel'; +import { isNewTabTrigger } from '@affine/core/utils'; import type { Filter } from '@affine/env/filter'; import { PlusIcon } from '@blocksuite/icons/rc'; import { useService, WorkspaceService } from '@toeverything/infra'; @@ -60,10 +61,10 @@ export const AllPageHeader = ({ !showCreateNew && styles.headerCreateNewButtonHidden )} onCreateEdgeless={e => - createEdgeless(e?.metaKey || e?.ctrlKey ? 'new-tab' : true) + createEdgeless(isNewTabTrigger(e) ? 'new-tab' : true) } onCreatePage={e => - createPage(e?.metaKey || e?.ctrlKey ? 'new-tab' : true) + createPage(isNewTabTrigger(e) ? 'new-tab' : true) } onImportFile={onImportFile} > diff --git a/packages/frontend/core/src/utils/event.ts b/packages/frontend/core/src/utils/event.ts new file mode 100644 index 0000000000..71786d1698 --- /dev/null +++ b/packages/frontend/core/src/utils/event.ts @@ -0,0 +1,14 @@ +import type { BaseSyntheticEvent } from 'react'; + +export function stopPropagation(event: BaseSyntheticEvent) { + event.stopPropagation(); +} + +export function stopEvent(event: BaseSyntheticEvent) { + event.stopPropagation(); + event.preventDefault(); +} + +export function isNewTabTrigger(event?: React.MouseEvent) { + return event ? event.ctrlKey || event.metaKey || event.button === 1 : false; +} diff --git a/packages/frontend/core/src/utils/index.ts b/packages/frontend/core/src/utils/index.ts index eaf45a6fa2..464497ff62 100644 --- a/packages/frontend/core/src/utils/index.ts +++ b/packages/frontend/core/src/utils/index.ts @@ -1,4 +1,5 @@ export * from './create-emotion-cache'; +export * from './event'; export * from './fractional-indexing'; export * from './popup'; export * from './string2color'; diff --git a/tests/affine-local/e2e/local-first-favorite-page.spec.ts b/tests/affine-local/e2e/local-first-favorite-page.spec.ts index fca397cb26..4d8b06cf3e 100644 --- a/tests/affine-local/e2e/local-first-favorite-page.spec.ts +++ b/tests/affine-local/e2e/local-first-favorite-page.spec.ts @@ -10,7 +10,7 @@ import { import { waitForLogMessage } from '@affine-test/kit/utils/utils'; import { expect } from '@playwright/test'; -test('New a page and open it ,then favorite it', async ({ +test('New a page and open it, then favorite it', async ({ page, workspace, }) => { diff --git a/tests/affine-local/e2e/local-first-openpage-newtab.spec.ts b/tests/affine-local/e2e/local-first-openpage-newtab.spec.ts index 0f2ae2036e..c66ebb087d 100644 --- a/tests/affine-local/e2e/local-first-openpage-newtab.spec.ts +++ b/tests/affine-local/e2e/local-first-openpage-newtab.spec.ts @@ -8,7 +8,7 @@ import { } from '@affine-test/kit/utils/page-logic'; import { expect } from '@playwright/test'; -test('click btn bew page and open in tab', async ({ page, workspace }) => { +test('click btn new page and open in tab', async ({ page, workspace }) => { await openHomePage(page); await waitForEditorLoad(page); await clickNewPageButton(page); @@ -31,3 +31,54 @@ test('click btn bew page and open in tab', async ({ page, workspace }) => { expect(currentWorkspace.meta.flavour).toContain('local'); }); + +test('switch between new page and all page', async ({ page }) => { + await openHomePage(page); + await waitForEditorLoad(page); + + const title = 'this is a new page'; + + await clickNewPageButton(page, title); + await page.getByTestId('all-pages').click(); + + const cell = page.getByTestId('page-list-item').getByText(title); + await expect(cell).toBeVisible(); + + await cell.click(); + await expect(getBlockSuiteEditorTitle(page)).toHaveText(title); + + await page.getByTestId('all-pages').click(); + await expect(cell).toBeVisible(); +}); + +test('ctrl click all page and open in new tab', async ({ page }) => { + await openHomePage(page); + await waitForEditorLoad(page); + + const [newTabPage] = await Promise.all([ + page.waitForEvent('popup'), + page.getByTestId('all-pages').click({ + modifiers: ['ControlOrMeta'], + }), + ]); + + await expect(newTabPage).toHaveURL(/\/all/, { + timeout: 15000, + }); +}); + +test('mid click all page and open in new tab', async ({ page }) => { + await openHomePage(page); + await waitForEditorLoad(page); + + const [newTabPage] = await Promise.all([ + page.waitForEvent('popup'), + page.getByTestId('all-pages').click({ + button: 'middle', + }), + ]); + + await expect(newTabPage).toHaveURL(/\/all/, { + timeout: 15000, + }); +});