refactor: remove NoSsr on top level (#1951)

This commit is contained in:
Himself65
2023-04-14 17:07:41 -05:00
committed by GitHub
parent 43a96fe8e3
commit 2383165470
27 changed files with 211 additions and 133 deletions

View File

@@ -75,6 +75,7 @@ __metadata:
clsx: ^1.2.1 clsx: ^1.2.1
concurrently: ^8.0.1 concurrently: ^8.0.1
jest-mock: ^29.5.0 jest-mock: ^29.5.0
jotai: ^2.0.4
kebab-case: ^1.0.2 kebab-case: ^1.0.2
lit: ^2.7.2 lit: ^2.7.2
lottie-web: ^5.11.0 lottie-web: ^5.11.0
@@ -92,11 +93,11 @@ __metadata:
wait-on: ^7.0.1 wait-on: ^7.0.1
yjs: ^13.5.52 yjs: ^13.5.52
peerDependencies: peerDependencies:
"@blocksuite/blocks": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/blocks": "*"
"@blocksuite/editor": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/editor": "*"
"@blocksuite/global": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/global": "*"
"@blocksuite/icons": 2.1.10 "@blocksuite/icons": "*"
"@blocksuite/store": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/store": "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -175,9 +176,17 @@ __metadata:
resolution: "@affine/jotai@workspace:../../packages/jotai" resolution: "@affine/jotai@workspace:../../packages/jotai"
dependencies: dependencies:
"@affine/env": "workspace:*" "@affine/env": "workspace:*"
"@blocksuite/blocks": 0.0.0-20230413190748-4d32b79a-nightly
"@blocksuite/editor": 0.0.0-20230413190748-4d32b79a-nightly
"@blocksuite/global": 0.0.0-20230413190748-4d32b79a-nightly
"@blocksuite/store": 0.0.0-20230413190748-4d32b79a-nightly
jotai: ^2.0.4 jotai: ^2.0.4
lottie-web: ^5.11.0 lottie-web: ^5.11.0
peerDependencies: peerDependencies:
"@blocksuite/blocks": "*"
"@blocksuite/editor": "*"
"@blocksuite/global": "*"
"@blocksuite/store": "*"
lottie-web: "*" lottie-web: "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -219,8 +228,8 @@ __metadata:
yjs: ^13.5.52 yjs: ^13.5.52
zod: ^3.21.4 zod: ^3.21.4
peerDependencies: peerDependencies:
"@blocksuite/blocks": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/blocks": "*"
"@blocksuite/store": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/store": "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft

View File

@@ -9,13 +9,17 @@ import { affineApis } from '../../shared/apis';
function createPublicWorkspace( function createPublicWorkspace(
workspaceId: string, workspaceId: string,
binary: ArrayBuffer binary: ArrayBuffer,
singlePage = false
): AffinePublicWorkspace { ): AffinePublicWorkspace {
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace( const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
workspaceId, workspaceId,
(k: string) => (k: string) =>
// fixme: token could be expired // fixme: token could be expired
({ api: `api/workspace`, token: getLoginStorage()?.token }[k]) ({ api: `api/workspace`, token: getLoginStorage()?.token }[k]),
{
cachePrefix: WorkspaceFlavour.PUBLIC + (singlePage ? '-single-page' : ''),
}
); );
BlockSuiteWorkspace.Y.applyUpdate( BlockSuiteWorkspace.Y.applyUpdate(
blockSuiteWorkspace.doc, blockSuiteWorkspace.doc,
@@ -49,7 +53,7 @@ export const publicPageBlockSuiteAtom = atom<Promise<AffinePublicWorkspace>>(
workspaceId, workspaceId,
pageId pageId
); );
return createPublicWorkspace(workspaceId, binary); return createPublicWorkspace(workspaceId, binary, true);
} }
); );
export const publicWorkspaceAtom = atom<Promise<AffinePublicWorkspace>>( export const publicWorkspaceAtom = atom<Promise<AffinePublicWorkspace>>(
@@ -59,6 +63,6 @@ export const publicWorkspaceAtom = atom<Promise<AffinePublicWorkspace>>(
throw new Error('No workspace id'); throw new Error('No workspace id');
} }
const binary = await affineApis.downloadWorkspace(workspaceId, true); const binary = await affineApis.downloadWorkspace(workspaceId, true);
return createPublicWorkspace(workspaceId, binary); return createPublicWorkspace(workspaceId, binary, false);
} }
); );

View File

@@ -1,4 +1,3 @@
'use client';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils'; import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import type { EditorContainer } from '@blocksuite/editor'; import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
@@ -11,7 +10,9 @@ import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace( const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
'test', 'test',
_ => undefined, _ => undefined,
Generator.AutoIncrement {
idGenerator: Generator.AutoIncrement,
}
); );
const page = blockSuiteWorkspace.createPage('page0'); const page = blockSuiteWorkspace.createPage('page0');

View File

@@ -89,8 +89,8 @@ const PublishPanelAffine: React.FC<PublishPanelAffineProps> = ({
<Wrapper marginBottom="42px">{t('Publishing Description')}</Wrapper> <Wrapper marginBottom="42px">{t('Publishing Description')}</Wrapper>
<Button <Button
data-testid="publish-to-web-button" data-testid="publish-to-web-button"
onClick={() => { onClick={async () => {
publishWorkspace(true); await publishWorkspace(true);
}} }}
type="light" type="light"
shape="circle" shape="circle"

View File

@@ -5,12 +5,13 @@ import { useBlockSuiteWorkspacePageTitle } from '@toeverything/hooks/use-blocksu
import { useAtomValue, useSetAtom } from 'jotai'; import { useAtomValue, useSetAtom } from 'jotai';
import Head from 'next/head'; import Head from 'next/head';
import type React from 'react'; import type React from 'react';
import { lazy, startTransition, Suspense, useCallback } from 'react'; import { startTransition, useCallback } from 'react';
import { currentEditorAtom, workspacePreferredModeAtom } from '../atoms'; import { currentEditorAtom, workspacePreferredModeAtom } from '../atoms';
import { usePageMeta } from '../hooks/use-page-meta'; import { usePageMeta } from '../hooks/use-page-meta';
import type { AffineOfficialWorkspace } from '../shared'; import type { AffineOfficialWorkspace } from '../shared';
import { PageNotFoundError } from './affine/affine-error-eoundary'; import { PageNotFoundError } from './affine/affine-error-eoundary';
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
import { WorkspaceHeader } from './blocksuite/workspace-header'; import { WorkspaceHeader } from './blocksuite/workspace-header';
export type PageDetailEditorProps = { export type PageDetailEditorProps = {
@@ -23,12 +24,6 @@ export type PageDetailEditorProps = {
header?: React.ReactNode; header?: React.ReactNode;
}; };
const Editor = lazy(() =>
import('./blocksuite/block-suite-editor').then(module => ({
default: module.BlockSuiteEditor,
}))
);
export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({ export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
workspace, workspace,
pageId, pageId,
@@ -64,34 +59,32 @@ export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
> >
{header} {header}
</WorkspaceHeader> </WorkspaceHeader>
<Suspense> <Editor
<Editor style={{
style={{ height: 'calc(100% - 52px)',
height: 'calc(100% - 52px)', }}
}} key={`${workspace.flavour}-${workspace.id}-${[pageId]}`}
key={pageId} mode={isPublic ? 'page' : currentMode}
mode={isPublic ? 'page' : currentMode} page={page}
page={page} onInit={useCallback(
onInit={useCallback( (page: Page, editor: Readonly<EditorContainer>) => {
(page: Page, editor: Readonly<EditorContainer>) => { startTransition(() => {
startTransition(() => { setEditor(editor);
setEditor(editor); });
}); onInit(page, editor);
onInit(page, editor); },
}, [onInit, setEditor]
[onInit, setEditor] )}
)} onLoad={useCallback(
onLoad={useCallback( (page: Page, editor: EditorContainer) => {
(page: Page, editor: EditorContainer) => { startTransition(() => {
startTransition(() => { setEditor(editor);
setEditor(editor); });
}); onLoad?.(page, editor);
onLoad?.(page, editor); },
}, [onLoad, setEditor]
[onLoad, setEditor] )}
)} />
/>
</Suspense>
</> </>
); );
}; };

View File

@@ -3,7 +3,7 @@ import { useEffect } from 'react';
import { currentEditorAtom } from '../../atoms'; import { currentEditorAtom } from '../../atoms';
export function useReferenceLink(props?: { export function useReferenceLinkEffect(props?: {
pageLinkClicked?: (params: { pageId: string }) => void; pageLinkClicked?: (params: { pageId: string }) => void;
subpageLinked?: (params: { pageId: string }) => void; subpageLinked?: (params: { pageId: string }) => void;
subpageUnlinked?: (params: { pageId: string }) => void; subpageUnlinked?: (params: { pageId: string }) => void;

View File

@@ -15,10 +15,8 @@ export function useToggleWorkspacePublish(workspace: AffineWorkspace) {
public: isPublish, public: isPublish,
}); });
await mutate(QueryKey.getWorkspaces); await mutate(QueryKey.getWorkspaces);
// force update // fixme: remove force update
jotaiStore.set(jotaiWorkspacesAtom, [ jotaiStore.set(jotaiWorkspacesAtom, ws => [...ws]);
...jotaiStore.get(jotaiWorkspacesAtom),
]);
}, },
[mutate, workspace.id] [mutate, workspace.id]
); );

View File

@@ -9,7 +9,6 @@ import {
import type { WorkspaceRegistry } from '@affine/workspace/type'; import type { WorkspaceRegistry } from '@affine/workspace/type';
import { WorkspaceFlavour } from '@affine/workspace/type'; import { WorkspaceFlavour } from '@affine/workspace/type';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import { useRouter } from 'next/router';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { affineAuth } from '../../plugins/affine'; import { affineAuth } from '../../plugins/affine';
@@ -18,7 +17,6 @@ import { useTransformWorkspace } from '../use-transform-workspace';
export function useOnTransformWorkspace() { export function useOnTransformWorkspace() {
const transformWorkspace = useTransformWorkspace(); const transformWorkspace = useTransformWorkspace();
const setUser = useSetAtom(currentAffineUserAtom); const setUser = useSetAtom(currentAffineUserAtom);
const router = useRouter();
return useCallback( return useCallback(
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>( async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
from: From, from: From,
@@ -35,13 +33,6 @@ export function useOnTransformWorkspace() {
} }
} }
const workspaceId = await transformWorkspace(from, to, workspace); const workspaceId = await transformWorkspace(from, to, workspace);
await router.replace({
pathname: `/workspace/[workspaceId]/setting`,
query: {
...router.query,
workspaceId,
},
});
window.dispatchEvent( window.dispatchEvent(
new CustomEvent('affine-workspace:transform', { new CustomEvent('affine-workspace:transform', {
detail: { detail: {
@@ -53,6 +44,6 @@ export function useOnTransformWorkspace() {
}) })
); );
}, },
[router, setUser, transformWorkspace] [setUser, transformWorkspace]
); );
} }

View File

@@ -25,6 +25,26 @@ export function useRouterHelper(router: NextRouter) {
}, },
[router] [router]
); );
const jumpToWorkspace = useCallback(
(workspaceId: string, logic: RouteLogic = RouteLogic.PUSH) => {
if (router.pathname === '/workspace/[workspaceId]/[pageId]') {
return router[logic]({
pathname: `/workspace/[workspaceId]`,
query: {
workspaceId: workspaceId,
},
});
} else {
return router[logic]({
pathname: router.pathname,
query: {
workspaceId: workspaceId,
},
});
}
},
[router]
);
const jumpToPublicWorkspacePage = useCallback( const jumpToPublicWorkspacePage = useCallback(
( (
workspaceId: string, workspaceId: string,
@@ -71,6 +91,7 @@ export function useRouterHelper(router: NextRouter) {
return { return {
jumpToPage, jumpToPage,
jumpToWorkspace,
jumpToPublicWorkspacePage, jumpToPublicWorkspacePage,
jumpToSubPath, jumpToSubPath,
openPage, openPage,

View File

@@ -2,9 +2,11 @@ import { jotaiWorkspacesAtom } from '@affine/workspace/atom';
import type { WorkspaceFlavour } from '@affine/workspace/type'; import type { WorkspaceFlavour } from '@affine/workspace/type';
import type { WorkspaceRegistry } from '@affine/workspace/type'; import type { WorkspaceRegistry } from '@affine/workspace/type';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import { useRouter } from 'next/router';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { WorkspacePlugins } from '../plugins'; import { WorkspacePlugins } from '../plugins';
import { useRouterHelper } from './use-router-helper';
/** /**
* Transform workspace from one flavour to another * Transform workspace from one flavour to another
@@ -13,6 +15,8 @@ import { WorkspacePlugins } from '../plugins';
*/ */
export function useTransformWorkspace() { export function useTransformWorkspace() {
const set = useSetAtom(jotaiWorkspacesAtom); const set = useSetAtom(jotaiWorkspacesAtom);
const router = useRouter();
const helper = useRouterHelper(router);
return useCallback( return useCallback(
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>( async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
from: From, from: From,
@@ -31,8 +35,9 @@ export function useTransformWorkspace() {
}); });
return [...workspaces]; return [...workspaces];
}); });
await helper.jumpToWorkspace(newId);
return newId; return newId;
}, },
[set] [helper, set]
); );
} }

View File

@@ -5,7 +5,6 @@ import { createAffineGlobalChannel } from '@affine/workspace/affine/sync';
import { jotaiStore, jotaiWorkspacesAtom } from '@affine/workspace/atom'; import { jotaiStore, jotaiWorkspacesAtom } from '@affine/workspace/atom';
import { WorkspaceFlavour } from '@affine/workspace/type'; import { WorkspaceFlavour } from '@affine/workspace/type';
import { assertExists, nanoid } from '@blocksuite/store'; import { assertExists, nanoid } from '@blocksuite/store';
import { NoSsr } from '@mui/material';
import { useAtom, useAtomValue, useSetAtom } from 'jotai'; import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import Head from 'next/head'; import Head from 'next/head';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
@@ -179,13 +178,13 @@ export const WorkspaceLayout: FC<PropsWithChildren> =
} }
}, [currentWorkspaceId, jotaiWorkspaces]); }, [currentWorkspaceId, jotaiWorkspaces]);
return ( return (
<NoSsr> <>
{/* fixme(himself65): don't re-render whole modals */} {/* fixme(himself65): don't re-render whole modals */}
<ModalProvider key={currentWorkspaceId} /> <ModalProvider key={currentWorkspaceId} />
<Suspense fallback={<PageLoading />}> <Suspense fallback={<PageLoading />}>
<WorkspaceLayoutInner>{children}</WorkspaceLayoutInner> <WorkspaceLayoutInner>{children}</WorkspaceLayoutInner>
</Suspense> </Suspense>
</NoSsr> </>
); );
}; };

View File

@@ -1,10 +1,9 @@
import { NoSsr } from '@mui/material';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { lazy, Suspense } from 'react'; import { lazy, Suspense } from 'react';
import { StyledPage, StyledWrapper } from '../../layouts/styles'; import { StyledPage, StyledWrapper } from '../../layouts/styles';
import type { NextPageWithLayout } from '../../shared'; import type { NextPageWithLayout } from '../../shared';
import { initPage } from '../../utils/blocksuite'; import { initPage } from '../../utils';
const Editor = lazy(() => const Editor = lazy(() =>
import('../../components/__debug__/client/Editor').then(module => ({ import('../../components/__debug__/client/Editor').then(module => ({
@@ -36,7 +35,3 @@ const InitPagePage: NextPageWithLayout = () => {
}; };
export default InitPagePage; export default InitPagePage;
InitPagePage.getLayout = page => {
return <NoSsr>{page}</NoSsr>;
};

View File

@@ -4,10 +4,10 @@ import { PageIcon } from '@blocksuite/icons';
import { assertExists } from '@blocksuite/store'; import { assertExists } from '@blocksuite/store';
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-blocksuite-workspace-avatar-url'; import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-blocksuite-workspace-avatar-url';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-blocksuite-workspace-name';
import { useAtomValue, useSetAtom } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import type React from 'react'; import type { ReactElement } from 'react';
import { Suspense, useCallback, useEffect } from 'react'; import { Suspense, useCallback, useEffect } from 'react';
import { import {
@@ -15,11 +15,10 @@ import {
publicWorkspaceIdAtom, publicWorkspaceIdAtom,
publicWorkspacePageIdAtom, publicWorkspacePageIdAtom,
} from '../../../atoms/public-workspace'; } from '../../../atoms/public-workspace';
import { QueryParamError } from '../../../components/affine/affine-error-eoundary';
import { PageDetailEditor } from '../../../components/page-detail-editor'; import { PageDetailEditor } from '../../../components/page-detail-editor';
import { WorkspaceAvatar } from '../../../components/pure/footer'; import { WorkspaceAvatar } from '../../../components/pure/footer';
import { PageLoading } from '../../../components/pure/loading'; import { PageLoading } from '../../../components/pure/loading';
import { useReferenceLink } from '../../../hooks/affine/use-reference-link'; import { useReferenceLinkEffect } from '../../../hooks/affine/use-reference-link-effect';
import { useRouterHelper } from '../../../hooks/use-router-helper'; import { useRouterHelper } from '../../../hooks/use-router-helper';
import { import {
PublicQuickSearch, PublicQuickSearch,
@@ -55,9 +54,9 @@ export const StyledBreadcrumbs = styled(Link)(({ theme }) => {
}; };
}); });
const PublicWorkspaceDetailPageInner: React.FC<{ const PublicWorkspaceDetailPageInner = (): ReactElement => {
pageId: string; const pageId = useAtomValue(publicWorkspacePageIdAtom);
}> = ({ pageId }) => { assertExists(pageId, 'pageId is null');
const publicWorkspace = useAtomValue(publicPageBlockSuiteAtom); const publicWorkspace = useAtomValue(publicPageBlockSuiteAtom);
const blockSuiteWorkspace = publicWorkspace.blockSuiteWorkspace; const blockSuiteWorkspace = publicWorkspace.blockSuiteWorkspace;
if (!blockSuiteWorkspace) { if (!blockSuiteWorkspace) {
@@ -65,10 +64,9 @@ const PublicWorkspaceDetailPageInner: React.FC<{
} }
const router = useRouter(); const router = useRouter();
const { openPage } = useRouterHelper(router); const { openPage } = useRouterHelper(router);
useReferenceLink({ useReferenceLinkEffect({
pageLinkClicked: useCallback( pageLinkClicked: useCallback(
({ pageId }: { pageId: string }) => { ({ pageId }: { pageId: string }) => {
assertExists(currentWorkspace);
return openPage(blockSuiteWorkspace.id, pageId); return openPage(blockSuiteWorkspace.id, pageId);
}, },
[blockSuiteWorkspace.id, openPage] [blockSuiteWorkspace.id, openPage]
@@ -115,31 +113,31 @@ const PublicWorkspaceDetailPageInner: React.FC<{
export const PublicWorkspaceDetailPage: NextPageWithLayout = () => { export const PublicWorkspaceDetailPage: NextPageWithLayout = () => {
const router = useRouter(); const router = useRouter();
const workspaceId = router.query.workspaceId; const [workspaceId, setWorkspaceId] = useAtom(publicWorkspaceIdAtom);
const pageId = router.query.pageId; const [pageId, setPageId] = useAtom(publicWorkspacePageIdAtom);
const setWorkspaceId = useSetAtom(publicWorkspaceIdAtom);
const setPageId = useSetAtom(publicWorkspacePageIdAtom);
useEffect(() => { useEffect(() => {
if (!router.isReady) { if (!router.isReady) {
return; return;
} }
if (typeof workspaceId === 'string') { if (typeof router.query.workspaceId === 'string') {
setWorkspaceId(workspaceId); setWorkspaceId(router.query.workspaceId);
} }
if (typeof pageId === 'string') { if (typeof router.query.pageId === 'string') {
setPageId(pageId); setPageId(router.query.pageId);
} }
}, [pageId, router.isReady, setPageId, setWorkspaceId, workspaceId]); }, [
const value = useAtomValue(publicWorkspaceIdAtom); router.isReady,
if (!router.isReady || !value) { router.query.pageId,
router.query.workspaceId,
setPageId,
setWorkspaceId,
]);
if (!router.isReady || !workspaceId || !pageId) {
return <PageLoading />; return <PageLoading />;
} }
if (typeof workspaceId !== 'string' || typeof pageId !== 'string') {
throw new QueryParamError('workspaceId, pageId', workspaceId);
}
return ( return (
<Suspense fallback={<PageLoading />}> <Suspense fallback={<PageLoading />}>
<PublicWorkspaceDetailPageInner pageId={pageId} /> <PublicWorkspaceDetailPageInner />
</Suspense> </Suspense>
); );
}; };

View File

@@ -6,7 +6,7 @@ import { useCallback, useEffect } from 'react';
import { Unreachable } from '../../../components/affine/affine-error-eoundary'; import { Unreachable } from '../../../components/affine/affine-error-eoundary';
import { PageLoading } from '../../../components/pure/loading'; import { PageLoading } from '../../../components/pure/loading';
import { useReferenceLink } from '../../../hooks/affine/use-reference-link'; import { useReferenceLinkEffect } from '../../../hooks/affine/use-reference-link-effect';
import { useCurrentPageId } from '../../../hooks/current/use-current-page-id'; import { useCurrentPageId } from '../../../hooks/current/use-current-page-id';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace'; import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { usePageMeta, usePageMetaHelper } from '../../../hooks/use-page-meta'; import { usePageMeta, usePageMetaHelper } from '../../../hooks/use-page-meta';
@@ -43,7 +43,7 @@ const WorkspaceDetail: React.FC = () => {
useSyncRecentViewsWithRouter(router); useSyncRecentViewsWithRouter(router);
useReferenceLink({ useReferenceLinkEffect({
pageLinkClicked: useCallback( pageLinkClicked: useCallback(
({ pageId }: { pageId: string }) => { ({ pageId }: { pageId: string }) => {
assertExists(currentWorkspace); assertExists(currentWorkspace);

View File

@@ -13,11 +13,11 @@
"./*": "./src/components/*/index.tsx" "./*": "./src/components/*/index.tsx"
}, },
"peerDependencies": { "peerDependencies": {
"@blocksuite/blocks": "0.0.0-20230409084303-221991d4-nightly", "@blocksuite/blocks": "*",
"@blocksuite/editor": "0.0.0-20230409084303-221991d4-nightly", "@blocksuite/editor": "*",
"@blocksuite/global": "0.0.0-20230409084303-221991d4-nightly", "@blocksuite/global": "*",
"@blocksuite/icons": "2.1.10", "@blocksuite/icons": "*",
"@blocksuite/store": "0.0.0-20230409084303-221991d4-nightly" "@blocksuite/store": "*"
}, },
"dependencies": { "dependencies": {
"@affine/debug": "workspace:*", "@affine/debug": "workspace:*",
@@ -36,6 +36,7 @@
"@radix-ui/react-avatar": "^1.0.2", "@radix-ui/react-avatar": "^1.0.2",
"@toeverything/hooks": "workspace:*", "@toeverything/hooks": "workspace:*",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"jotai": "^2.0.4",
"kebab-case": "^1.0.2", "kebab-case": "^1.0.2",
"lit": "^2.7.2", "lit": "^2.7.2",
"lottie-web": "^5.11.0", "lottie-web": "^5.11.0",

View File

@@ -59,13 +59,13 @@ const Template: StoryFn<EditorProps> = (props: EditorProps) => {
export const Empty = Template.bind({}); export const Empty = Template.bind({});
Empty.play = async ({ canvasElement }) => { Empty.play = async ({ canvasElement }) => {
await new Promise<void>(resolve => {
setTimeout(() => resolve(), 500);
});
const editorContainer = canvasElement.querySelector( const editorContainer = canvasElement.querySelector(
'[data-testid="editor-page0"]' '[data-testid="editor-page0"]'
) as HTMLDivElement; ) as HTMLDivElement;
expect(editorContainer).not.toBeNull(); expect(editorContainer).not.toBeNull();
await new Promise<void>(resolve => {
setTimeout(() => resolve(), 50);
});
const editor = editorContainer.querySelector( const editor = editorContainer.querySelector(
'editor-container' 'editor-container'
) as EditorContainer; ) as EditorContainer;

View File

@@ -1,9 +1,11 @@
import { editorContainerModuleAtom } from '@affine/jotai';
import type { BlockHub } from '@blocksuite/blocks'; import type { BlockHub } from '@blocksuite/blocks';
import { EditorContainer } from '@blocksuite/editor'; import type { EditorContainer } from '@blocksuite/editor';
import { assertExists } from '@blocksuite/global/utils'; import { assertExists } from '@blocksuite/global/utils';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import { useAtomValue } from 'jotai';
import type { CSSProperties, ReactElement } from 'react'; import type { CSSProperties, ReactElement } from 'react';
import { memo, useCallback, useEffect, useRef } from 'react'; import { memo, Suspense, useCallback, useEffect, useRef } from 'react';
import type { FallbackProps } from 'react-error-boundary'; import type { FallbackProps } from 'react-error-boundary';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
@@ -27,12 +29,15 @@ declare global {
} }
const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => { const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
const JotaiEditorContainer = useAtomValue(
editorContainerModuleAtom
) as typeof EditorContainer;
const page = props.page; const page = props.page;
assertExists(page, 'page should not be null'); assertExists(page, 'page should not be null');
const editorRef = useRef<EditorContainer | null>(null); const editorRef = useRef<EditorContainer | null>(null);
const blockHubRef = useRef<BlockHub | null>(null); const blockHubRef = useRef<BlockHub | null>(null);
if (editorRef.current === null) { if (editorRef.current === null) {
editorRef.current = new EditorContainer(); editorRef.current = new JotaiEditorContainer();
editorRef.current.autofocus = true; editorRef.current.autofocus = true;
globalThis.currentEditor = editorRef.current; globalThis.currentEditor = editorRef.current;
} }
@@ -83,7 +88,7 @@ const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
blockHubRef.current?.remove(); blockHubRef.current?.remove();
container.removeChild(editor); container.removeChild(editor);
}; };
}, [page]); }, [editor, page]);
return ( return (
<div <div
data-testid={`editor-${props.page.id}`} data-testid={`editor-${props.page.id}`}
@@ -126,7 +131,9 @@ export const BlockSuiteEditor = memo(function BlockSuiteEditor(
[props.onReset] [props.onReset]
)} )}
> >
<BlockSuiteEditorImpl {...props} /> <Suspense fallback={null}>
<BlockSuiteEditorImpl {...props} />
</Suspense>
</ErrorBoundary> </ErrorBoundary>
); );
}); });

View File

@@ -7,9 +7,17 @@
"jotai": "^2.0.4" "jotai": "^2.0.4"
}, },
"devDependencies": { "devDependencies": {
"@blocksuite/blocks": "0.0.0-20230413190748-4d32b79a-nightly",
"@blocksuite/editor": "0.0.0-20230413190748-4d32b79a-nightly",
"@blocksuite/global": "0.0.0-20230413190748-4d32b79a-nightly",
"@blocksuite/store": "0.0.0-20230413190748-4d32b79a-nightly",
"lottie-web": "^5.11.0" "lottie-web": "^5.11.0"
}, },
"peerDependencies": { "peerDependencies": {
"@blocksuite/blocks": "*",
"@blocksuite/editor": "*",
"@blocksuite/global": "*",
"@blocksuite/store": "*",
"lottie-web": "*" "lottie-web": "*"
} }
} }

View File

@@ -1,5 +1,14 @@
import { getEnvironment } from '@affine/env';
import type { EditorContainer } from '@blocksuite/editor';
import { atom } from 'jotai'; import { atom } from 'jotai';
export const lottieAtom = atom(async () => export const lottieAtom = atom(import('lottie-web').then(m => m.default));
import('lottie-web').then(m => m.default)
export const editorContainerModuleAtom = atom<Promise<typeof EditorContainer>>(
getEnvironment().isServer
? async () =>
import('@blocksuite/editor').then(module => module.EditorContainer)
: (import('@blocksuite/editor').then(
module => module.EditorContainer
) as any)
); );

View File

@@ -13,8 +13,8 @@
"./affine/keck": "./src/affine/keck/index.ts" "./affine/keck": "./src/affine/keck/index.ts"
}, },
"peerDependencies": { "peerDependencies": {
"@blocksuite/blocks": "0.0.0-20230409084303-221991d4-nightly", "@blocksuite/blocks": "*",
"@blocksuite/store": "0.0.0-20230409084303-221991d4-nightly" "@blocksuite/store": "*"
}, },
"dependencies": { "dependencies": {
"@affine-test/fixtures": "workspace:*", "@affine-test/fixtures": "workspace:*",

View File

@@ -57,6 +57,7 @@ export const isExpired = (
}; };
export const setLoginStorage = (login: LoginResponse) => { export const setLoginStorage = (login: LoginResponse) => {
loginResponseSchema.parse(login);
localStorage.setItem( localStorage.setItem(
STORAGE_KEY, STORAGE_KEY,
JSON.stringify({ JSON.stringify({

View File

@@ -6,11 +6,17 @@ const hashMap = new Map<string, Workspace>();
export const createEmptyBlockSuiteWorkspace = ( export const createEmptyBlockSuiteWorkspace = (
id: string, id: string,
blobOptionsGetter?: BlobOptionsGetter, blobOptionsGetter?: BlobOptionsGetter,
idGenerator?: Generator config?: {
): Workspace => { cachePrefix?: string;
if (hashMap.has(id)) { idGenerator?: Generator;
return hashMap.get(id) as Workspace;
} }
): Workspace => {
const prefix: string = config?.cachePrefix ?? '';
const cacheKey = `${prefix}${id}`;
if (hashMap.has(cacheKey)) {
return hashMap.get(cacheKey) as Workspace;
}
const idGenerator = config?.idGenerator;
const workspace = new Workspace({ const workspace = new Workspace({
id, id,
isSSR: typeof window === 'undefined', isSSR: typeof window === 'undefined',
@@ -19,6 +25,6 @@ export const createEmptyBlockSuiteWorkspace = (
}) })
.register(AffineSchemas) .register(AffineSchemas)
.register(__unstableSchemas); .register(__unstableSchemas);
hashMap.set(id, workspace); hashMap.set(cacheKey, workspace);
return workspace; return workspace;
}; };

View File

@@ -76,8 +76,6 @@ const config: PlaywrightTestConfig = {
env: { env: {
COVERAGE: process.env.COVERAGE || 'false', COVERAGE: process.env.COVERAGE || 'false',
ENABLE_DEBUG_PAGE: '1', ENABLE_DEBUG_PAGE: '1',
ENABLE_SUBPAGE: '1',
ENABLE_CHANGELOG: '1',
API_SERVER_PROFILE: 'local', API_SERVER_PROFILE: 'local',
}, },
}, },

View File

@@ -0,0 +1,18 @@
import { vi } from 'vitest';
vi.mock('lottie-web', () => ({
default: {},
}));
vi.mock('@blocksuite/editor', () => ({
EditorContainer: vi.fn(),
}));
if (typeof window !== 'undefined' && HTMLCanvasElement) {
// @ts-expect-error
HTMLCanvasElement.prototype.getContext = () => {
return {
fillRect: vi.fn(),
};
};
}

View File

@@ -40,7 +40,14 @@ export const test = baseTest.extend({
} }
); );
} }
for (const page of context.pages()) {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
}
await use(context); await use(context);
if (enableCoverage) { if (enableCoverage) {
for (const page of context.pages()) { for (const page of context.pages()) {
await page.evaluate(() => await page.evaluate(() =>

View File

@@ -14,7 +14,7 @@ export default defineConfig({
}, },
}, },
test: { test: {
setupFiles: ['./scripts/setup/search.ts'], setupFiles: ['./scripts/setup/search.ts', './scripts/setup/lottie-web.ts'],
include: [ include: [
'packages/**/*.spec.ts', 'packages/**/*.spec.ts',
'packages/**/*.spec.tsx', 'packages/**/*.spec.tsx',

View File

@@ -75,6 +75,7 @@ __metadata:
clsx: ^1.2.1 clsx: ^1.2.1
concurrently: ^8.0.1 concurrently: ^8.0.1
jest-mock: ^29.5.0 jest-mock: ^29.5.0
jotai: ^2.0.4
kebab-case: ^1.0.2 kebab-case: ^1.0.2
lit: ^2.7.2 lit: ^2.7.2
lottie-web: ^5.11.0 lottie-web: ^5.11.0
@@ -92,11 +93,11 @@ __metadata:
wait-on: ^7.0.1 wait-on: ^7.0.1
yjs: ^13.5.52 yjs: ^13.5.52
peerDependencies: peerDependencies:
"@blocksuite/blocks": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/blocks": "*"
"@blocksuite/editor": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/editor": "*"
"@blocksuite/global": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/global": "*"
"@blocksuite/icons": 2.1.10 "@blocksuite/icons": "*"
"@blocksuite/store": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/store": "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -148,9 +149,17 @@ __metadata:
resolution: "@affine/jotai@workspace:packages/jotai" resolution: "@affine/jotai@workspace:packages/jotai"
dependencies: dependencies:
"@affine/env": "workspace:*" "@affine/env": "workspace:*"
"@blocksuite/blocks": 0.0.0-20230413190748-4d32b79a-nightly
"@blocksuite/editor": 0.0.0-20230413190748-4d32b79a-nightly
"@blocksuite/global": 0.0.0-20230413190748-4d32b79a-nightly
"@blocksuite/store": 0.0.0-20230413190748-4d32b79a-nightly
jotai: ^2.0.4 jotai: ^2.0.4
lottie-web: ^5.11.0 lottie-web: ^5.11.0
peerDependencies: peerDependencies:
"@blocksuite/blocks": "*"
"@blocksuite/editor": "*"
"@blocksuite/global": "*"
"@blocksuite/store": "*"
lottie-web: "*" lottie-web: "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -257,8 +266,8 @@ __metadata:
yjs: ^13.5.52 yjs: ^13.5.52
zod: ^3.21.4 zod: ^3.21.4
peerDependencies: peerDependencies:
"@blocksuite/blocks": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/blocks": "*"
"@blocksuite/store": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/store": "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft